]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Improve parallel scheduling logic in pg_dump/pg_restore.
[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-2018, 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 /*
138  * Macro for producing quoted, schema-qualified name of a dumpable object.
139  */
140 #define fmtQualifiedDumpable(obj) \
141         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
142                                    (obj)->dobj.name)
143
144 static void help(const char *progname);
145 static void setup_connection(Archive *AH,
146                                  const char *dumpencoding, const char *dumpsnapshot,
147                                  char *use_role);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(Archive *fout,
150                                                         SimpleStringList *patterns,
151                                                         SimpleOidList *oids,
152                                                         bool strict_names);
153 static void expand_table_name_patterns(Archive *fout,
154                                                    SimpleStringList *patterns,
155                                                    SimpleOidList *oids,
156                                                    bool strict_names);
157 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
158 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
159 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
160 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
161 static void dumpComment(Archive *fout, const char *type, const char *name,
162                         const char *namespace, const char *owner,
163                         CatalogId catalogId, int subid, DumpId dumpId);
164 static int findComments(Archive *fout, Oid classoid, Oid objoid,
165                          CommentItem **items);
166 static int      collectComments(Archive *fout, CommentItem **items);
167 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
168                          const char *namespace, const char *owner,
169                          CatalogId catalogId, int subid, DumpId dumpId);
170 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
171                           SecLabelItem **items);
172 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
173 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
174 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
175 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
176 static void dumpType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
179 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
181 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
182 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
183 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
184 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
185 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
186 static void dumpFunc(Archive *fout, FuncInfo *finfo);
187 static void dumpCast(Archive *fout, CastInfo *cast);
188 static void dumpTransform(Archive *fout, TransformInfo *transform);
189 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
190 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
191 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
192 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
193 static void dumpCollation(Archive *fout, CollInfo *collinfo);
194 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
195 static void dumpRule(Archive *fout, RuleInfo *rinfo);
196 static void dumpAgg(Archive *fout, AggInfo *agginfo);
197 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
198 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
199 static void dumpTable(Archive *fout, TableInfo *tbinfo);
200 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
201 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
202 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
203 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
204 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
205 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
206 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
207 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
208 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
209 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
210 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
211 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
212 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
213 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
214 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
215 static void dumpUserMappings(Archive *fout,
216                                  const char *servername, const char *namespace,
217                                  const char *owner, CatalogId catalogId, DumpId dumpId);
218 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
219
220 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
221                 const char *type, const char *name, const char *subname,
222                 const char *nspname, const char *owner,
223                 const char *acls, const char *racls,
224                 const char *initacls, const char *initracls);
225
226 static void getDependencies(Archive *fout);
227 static void BuildArchiveDependencies(Archive *fout);
228 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
229                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
230
231 static DumpableObject *createBoundaryObjects(void);
232 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
233                                                 DumpableObject *boundaryObjs);
234
235 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
236 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind);
237 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
238 static void buildMatViewRefreshDependencies(Archive *fout);
239 static void getTableDataFKConstraints(void);
240 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
241                                                   bool is_agg);
242 static char *format_function_arguments_old(Archive *fout,
243                                                           FuncInfo *finfo, int nallargs,
244                                                           char **allargtypes,
245                                                           char **argmodes,
246                                                           char **argnames);
247 static char *format_function_signature(Archive *fout,
248                                                   FuncInfo *finfo, bool honor_quotes);
249 static char *convertRegProcReference(Archive *fout,
250                                                 const char *proc);
251 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
252 static char *convertTSFunction(Archive *fout, Oid funcOid);
253 static Oid      findLastBuiltinOid_V71(Archive *fout);
254 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
255 static void getBlobs(Archive *fout);
256 static void dumpBlob(Archive *fout, BlobInfo *binfo);
257 static int      dumpBlobs(Archive *fout, void *arg);
258 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
259 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
260 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
261 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
262 static void dumpDatabase(Archive *AH);
263 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
264                                    const char *dbname, Oid dboid);
265 static void dumpEncoding(Archive *AH);
266 static void dumpStdStrings(Archive *AH);
267 static void dumpSearchPath(Archive *AH);
268 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
269                                                                                  PQExpBuffer upgrade_buffer,
270                                                                                  Oid pg_type_oid,
271                                                                                  bool force_array_type);
272 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
273                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
274 static void binary_upgrade_set_pg_class_oids(Archive *fout,
275                                                                  PQExpBuffer upgrade_buffer,
276                                                                  Oid pg_class_oid, bool is_index);
277 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
278                                                                 DumpableObject *dobj,
279                                                                 const char *objtype,
280                                                                 const char *objname,
281                                                                 const char *objnamespace);
282 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
283 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
284 static bool nonemptyReloptions(const char *reloptions);
285 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
286                                                 const char *prefix, Archive *fout);
287 static char *get_synchronized_snapshot(Archive *fout);
288 static void setupDumpWorker(Archive *AHX);
289 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
290
291
292 int
293 main(int argc, char **argv)
294 {
295         int                     c;
296         const char *filename = NULL;
297         const char *format = "p";
298         TableInfo  *tblinfo;
299         int                     numTables;
300         DumpableObject **dobjs;
301         int                     numObjs;
302         DumpableObject *boundaryObjs;
303         int                     i;
304         int                     optindex;
305         RestoreOptions *ropt;
306         Archive    *fout;                       /* the script file */
307         const char *dumpencoding = NULL;
308         const char *dumpsnapshot = NULL;
309         char       *use_role = NULL;
310         int                     numWorkers = 1;
311         trivalue        prompt_password = TRI_DEFAULT;
312         int                     compressLevel = -1;
313         int                     plainText = 0;
314         ArchiveFormat archiveFormat = archUnknown;
315         ArchiveMode archiveMode;
316
317         static DumpOptions dopt;
318
319         static struct option long_options[] = {
320                 {"data-only", no_argument, NULL, 'a'},
321                 {"blobs", no_argument, NULL, 'b'},
322                 {"no-blobs", no_argument, NULL, 'B'},
323                 {"clean", no_argument, NULL, 'c'},
324                 {"create", no_argument, NULL, 'C'},
325                 {"dbname", required_argument, NULL, 'd'},
326                 {"file", required_argument, NULL, 'f'},
327                 {"format", required_argument, NULL, 'F'},
328                 {"host", required_argument, NULL, 'h'},
329                 {"jobs", 1, NULL, 'j'},
330                 {"no-reconnect", no_argument, NULL, 'R'},
331                 {"oids", no_argument, NULL, 'o'},
332                 {"no-owner", no_argument, NULL, 'O'},
333                 {"port", required_argument, NULL, 'p'},
334                 {"schema", required_argument, NULL, 'n'},
335                 {"exclude-schema", required_argument, NULL, 'N'},
336                 {"schema-only", no_argument, NULL, 's'},
337                 {"superuser", required_argument, NULL, 'S'},
338                 {"table", required_argument, NULL, 't'},
339                 {"exclude-table", required_argument, NULL, 'T'},
340                 {"no-password", no_argument, NULL, 'w'},
341                 {"password", no_argument, NULL, 'W'},
342                 {"username", required_argument, NULL, 'U'},
343                 {"verbose", no_argument, NULL, 'v'},
344                 {"no-privileges", no_argument, NULL, 'x'},
345                 {"no-acl", no_argument, NULL, 'x'},
346                 {"compress", required_argument, NULL, 'Z'},
347                 {"encoding", required_argument, NULL, 'E'},
348                 {"help", no_argument, NULL, '?'},
349                 {"version", no_argument, NULL, 'V'},
350
351                 /*
352                  * the following options don't have an equivalent short option letter
353                  */
354                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
355                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
356                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
357                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
358                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
359                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
360                 {"exclude-table-data", required_argument, NULL, 4},
361                 {"if-exists", no_argument, &dopt.if_exists, 1},
362                 {"inserts", no_argument, &dopt.dump_inserts, 1},
363                 {"lock-wait-timeout", required_argument, NULL, 2},
364                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
365                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
366                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
367                 {"role", required_argument, NULL, 3},
368                 {"section", required_argument, NULL, 5},
369                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
370                 {"snapshot", required_argument, NULL, 6},
371                 {"strict-names", no_argument, &strict_names, 1},
372                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
373                 {"no-comments", no_argument, &dopt.no_comments, 1},
374                 {"no-publications", no_argument, &dopt.no_publications, 1},
375                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
376                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
377                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
378                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
379                 {"no-sync", no_argument, NULL, 7},
380                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
381
382                 {NULL, 0, NULL, 0}
383         };
384
385         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
386
387         /*
388          * Initialize what we need for parallel execution, especially for thread
389          * support on Windows.
390          */
391         init_parallel_dump_utils();
392
393         g_verbose = false;
394
395         strcpy(g_comment_start, "-- ");
396         g_comment_end[0] = '\0';
397         strcpy(g_opaque_type, "opaque");
398
399         progname = get_progname(argv[0]);
400
401         if (argc > 1)
402         {
403                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
404                 {
405                         help(progname);
406                         exit_nicely(0);
407                 }
408                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
409                 {
410                         puts("pg_dump (PostgreSQL) " PG_VERSION);
411                         exit_nicely(0);
412                 }
413         }
414
415         InitDumpOptions(&dopt);
416
417         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
418                                                         long_options, &optindex)) != -1)
419         {
420                 switch (c)
421                 {
422                         case 'a':                       /* Dump data only */
423                                 dopt.dataOnly = true;
424                                 break;
425
426                         case 'b':                       /* Dump blobs */
427                                 dopt.outputBlobs = true;
428                                 break;
429
430                         case 'B':                       /* Don't dump blobs */
431                                 dopt.dontOutputBlobs = true;
432                                 break;
433
434                         case 'c':                       /* clean (i.e., drop) schema prior to create */
435                                 dopt.outputClean = 1;
436                                 break;
437
438                         case 'C':                       /* Create DB */
439                                 dopt.outputCreateDB = 1;
440                                 break;
441
442                         case 'd':                       /* database name */
443                                 dopt.dbname = pg_strdup(optarg);
444                                 break;
445
446                         case 'E':                       /* Dump encoding */
447                                 dumpencoding = pg_strdup(optarg);
448                                 break;
449
450                         case 'f':
451                                 filename = pg_strdup(optarg);
452                                 break;
453
454                         case 'F':
455                                 format = pg_strdup(optarg);
456                                 break;
457
458                         case 'h':                       /* server host */
459                                 dopt.pghost = pg_strdup(optarg);
460                                 break;
461
462                         case 'j':                       /* number of dump jobs */
463                                 numWorkers = atoi(optarg);
464                                 break;
465
466                         case 'n':                       /* include schema(s) */
467                                 simple_string_list_append(&schema_include_patterns, optarg);
468                                 dopt.include_everything = false;
469                                 break;
470
471                         case 'N':                       /* exclude schema(s) */
472                                 simple_string_list_append(&schema_exclude_patterns, optarg);
473                                 break;
474
475                         case 'o':                       /* Dump oids */
476                                 dopt.oids = true;
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                         default:
566                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
567                                 exit_nicely(1);
568                 }
569         }
570
571         /*
572          * Non-option argument specifies database name as long as it wasn't
573          * already specified with -d / --dbname
574          */
575         if (optind < argc && dopt.dbname == NULL)
576                 dopt.dbname = argv[optind++];
577
578         /* Complain if any arguments remain */
579         if (optind < argc)
580         {
581                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
582                                 progname, argv[optind]);
583                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
584                                 progname);
585                 exit_nicely(1);
586         }
587
588         /* --column-inserts implies --inserts */
589         if (dopt.column_inserts)
590                 dopt.dump_inserts = 1;
591
592         /*
593          * Binary upgrade mode implies dumping sequence data even in schema-only
594          * mode.  This is not exposed as a separate option, but kept separate
595          * internally for clarity.
596          */
597         if (dopt.binary_upgrade)
598                 dopt.sequence_data = 1;
599
600         if (dopt.dataOnly && dopt.schemaOnly)
601         {
602                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
603                 exit_nicely(1);
604         }
605
606         if (dopt.dataOnly && dopt.outputClean)
607         {
608                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
609                 exit_nicely(1);
610         }
611
612         if (dopt.dump_inserts && dopt.oids)
613         {
614                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
615                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
616                 exit_nicely(1);
617         }
618
619         if (dopt.if_exists && !dopt.outputClean)
620                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
621
622         if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
623                 exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
624
625         /* Identify archive format to emit */
626         archiveFormat = parseArchiveFormat(format, &archiveMode);
627
628         /* archiveFormat specific setup */
629         if (archiveFormat == archNull)
630                 plainText = 1;
631
632         /* Custom and directory formats are compressed by default, others not */
633         if (compressLevel == -1)
634         {
635 #ifdef HAVE_LIBZ
636                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
637                         compressLevel = Z_DEFAULT_COMPRESSION;
638                 else
639 #endif
640                         compressLevel = 0;
641         }
642
643 #ifndef HAVE_LIBZ
644         if (compressLevel != 0)
645                 write_msg(NULL, "WARNING: requested compression not available in this "
646                                   "installation -- archive will be uncompressed\n");
647         compressLevel = 0;
648 #endif
649
650         /*
651          * If emitting an archive format, we always want to emit a DATABASE item,
652          * in case --create is specified at pg_restore time.
653          */
654         if (!plainText)
655                 dopt.outputCreateDB = 1;
656
657         /*
658          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
659          * parallel jobs because that's the maximum limit for the
660          * WaitForMultipleObjects() call.
661          */
662         if (numWorkers <= 0
663 #ifdef WIN32
664                 || numWorkers > MAXIMUM_WAIT_OBJECTS
665 #endif
666                 )
667                 exit_horribly(NULL, "invalid number of parallel jobs\n");
668
669         /* Parallel backup only in the directory archive format so far */
670         if (archiveFormat != archDirectory && numWorkers > 1)
671                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
672
673         /* Open the output file */
674         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
675                                                  archiveMode, setupDumpWorker);
676
677         /* Make dump options accessible right away */
678         SetArchiveOptions(fout, &dopt, NULL);
679
680         /* Register the cleanup hook */
681         on_exit_close_archive(fout);
682
683         /* Let the archiver know how noisy to be */
684         fout->verbose = g_verbose;
685
686         /*
687          * We allow the server to be back to 8.0, and up to any minor release of
688          * our own major version.  (See also version check in pg_dumpall.c.)
689          */
690         fout->minRemoteVersion = 80000;
691         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
692
693         fout->numWorkers = numWorkers;
694
695         /*
696          * Open the database using the Archiver, so it knows about it. Errors mean
697          * death.
698          */
699         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
700         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
701
702         /*
703          * Disable security label support if server version < v9.1.x (prevents
704          * access to nonexistent pg_seclabel catalog)
705          */
706         if (fout->remoteVersion < 90100)
707                 dopt.no_security_labels = 1;
708
709         /*
710          * On hot standbys, never try to dump unlogged table data, since it will
711          * just throw an error.
712          */
713         if (fout->isStandby)
714                 dopt.no_unlogged_table_data = true;
715
716         /* Select the appropriate subquery to convert user IDs to names */
717         if (fout->remoteVersion >= 80100)
718                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
719         else
720                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
721
722         /* check the version for the synchronized snapshots feature */
723         if (numWorkers > 1 && fout->remoteVersion < 90200
724                 && !dopt.no_synchronized_snapshots)
725                 exit_horribly(NULL,
726                                           "Synchronized snapshots are not supported by this server version.\n"
727                                           "Run with --no-synchronized-snapshots instead if you do not need\n"
728                                           "synchronized snapshots.\n");
729
730         /* check the version when a snapshot is explicitly specified by user */
731         if (dumpsnapshot && fout->remoteVersion < 90200)
732                 exit_horribly(NULL,
733                                           "Exported snapshots are not supported by this server version.\n");
734
735         /*
736          * Find the last built-in OID, if needed (prior to 8.1)
737          *
738          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
739          */
740         if (fout->remoteVersion < 80100)
741                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
742         else
743                 g_last_builtin_oid = FirstNormalObjectId - 1;
744
745         if (g_verbose)
746                 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
747
748         /* Expand schema selection patterns into OID lists */
749         if (schema_include_patterns.head != NULL)
750         {
751                 expand_schema_name_patterns(fout, &schema_include_patterns,
752                                                                         &schema_include_oids,
753                                                                         strict_names);
754                 if (schema_include_oids.head == NULL)
755                         exit_horribly(NULL, "no matching schemas were found\n");
756         }
757         expand_schema_name_patterns(fout, &schema_exclude_patterns,
758                                                                 &schema_exclude_oids,
759                                                                 false);
760         /* non-matching exclusion patterns aren't an error */
761
762         /* Expand table selection patterns into OID lists */
763         if (table_include_patterns.head != NULL)
764         {
765                 expand_table_name_patterns(fout, &table_include_patterns,
766                                                                    &table_include_oids,
767                                                                    strict_names);
768                 if (table_include_oids.head == NULL)
769                         exit_horribly(NULL, "no matching tables were found\n");
770         }
771         expand_table_name_patterns(fout, &table_exclude_patterns,
772                                                            &table_exclude_oids,
773                                                            false);
774
775         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
776                                                            &tabledata_exclude_oids,
777                                                            false);
778
779         /* non-matching exclusion patterns aren't an error */
780
781         /*
782          * Dumping blobs is the default for dumps where an inclusion switch is not
783          * used (an "include everything" dump).  -B can be used to exclude blobs
784          * from those dumps.  -b can be used to include blobs even when an
785          * inclusion switch is used.
786          *
787          * -s means "schema only" and blobs are data, not schema, so we never
788          * include blobs when -s is used.
789          */
790         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
791                 dopt.outputBlobs = true;
792
793         /*
794          * Now scan the database and create DumpableObject structs for all the
795          * objects we intend to dump.
796          */
797         tblinfo = getSchemaData(fout, &numTables);
798
799         if (fout->remoteVersion < 80400)
800                 guessConstraintInheritance(tblinfo, numTables);
801
802         if (!dopt.schemaOnly)
803         {
804                 getTableData(&dopt, tblinfo, numTables, dopt.oids, 0);
805                 buildMatViewRefreshDependencies(fout);
806                 if (dopt.dataOnly)
807                         getTableDataFKConstraints();
808         }
809
810         if (dopt.schemaOnly && dopt.sequence_data)
811                 getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE);
812
813         /*
814          * In binary-upgrade mode, we do not have to worry about the actual blob
815          * data or the associated metadata that resides in the pg_largeobject and
816          * pg_largeobject_metadata tables, respectively.
817          *
818          * However, we do need to collect blob information as there may be
819          * comments or other information on blobs that we do need to dump out.
820          */
821         if (dopt.outputBlobs || dopt.binary_upgrade)
822                 getBlobs(fout);
823
824         /*
825          * Collect dependency data to assist in ordering the objects.
826          */
827         getDependencies(fout);
828
829         /* Lastly, create dummy objects to represent the section boundaries */
830         boundaryObjs = createBoundaryObjects();
831
832         /* Get pointers to all the known DumpableObjects */
833         getDumpableObjects(&dobjs, &numObjs);
834
835         /*
836          * Add dummy dependencies to enforce the dump section ordering.
837          */
838         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
839
840         /*
841          * Sort the objects into a safe dump order (no forward references).
842          *
843          * We rely on dependency information to help us determine a safe order, so
844          * the initial sort is mostly for cosmetic purposes: we sort by name to
845          * ensure that logically identical schemas will dump identically.
846          */
847         sortDumpableObjectsByTypeName(dobjs, numObjs);
848
849         sortDumpableObjects(dobjs, numObjs,
850                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
851
852         /*
853          * Create archive TOC entries for all the objects to be dumped, in a safe
854          * order.
855          */
856
857         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
858         dumpEncoding(fout);
859         dumpStdStrings(fout);
860         dumpSearchPath(fout);
861
862         /* The database items are always next, unless we don't want them at all */
863         if (dopt.outputCreateDB)
864                 dumpDatabase(fout);
865
866         /* Now the rearrangeable objects. */
867         for (i = 0; i < numObjs; i++)
868                 dumpDumpableObject(fout, dobjs[i]);
869
870         /*
871          * Set up options info to ensure we dump what we want.
872          */
873         ropt = NewRestoreOptions();
874         ropt->filename = filename;
875
876         /* if you change this list, see dumpOptionsFromRestoreOptions */
877         ropt->dropSchema = dopt.outputClean;
878         ropt->dataOnly = dopt.dataOnly;
879         ropt->schemaOnly = dopt.schemaOnly;
880         ropt->if_exists = dopt.if_exists;
881         ropt->column_inserts = dopt.column_inserts;
882         ropt->dumpSections = dopt.dumpSections;
883         ropt->aclsSkip = dopt.aclsSkip;
884         ropt->superuser = dopt.outputSuperuser;
885         ropt->createDB = dopt.outputCreateDB;
886         ropt->noOwner = dopt.outputNoOwner;
887         ropt->noTablespace = dopt.outputNoTablespaces;
888         ropt->disable_triggers = dopt.disable_triggers;
889         ropt->use_setsessauth = dopt.use_setsessauth;
890         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
891         ropt->dump_inserts = dopt.dump_inserts;
892         ropt->no_comments = dopt.no_comments;
893         ropt->no_publications = dopt.no_publications;
894         ropt->no_security_labels = dopt.no_security_labels;
895         ropt->no_subscriptions = dopt.no_subscriptions;
896         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
897         ropt->include_everything = dopt.include_everything;
898         ropt->enable_row_security = dopt.enable_row_security;
899         ropt->sequence_data = dopt.sequence_data;
900         ropt->binary_upgrade = dopt.binary_upgrade;
901
902         if (compressLevel == -1)
903                 ropt->compression = 0;
904         else
905                 ropt->compression = compressLevel;
906
907         ropt->suppressDumpWarnings = true;      /* We've already shown them */
908
909         SetArchiveOptions(fout, &dopt, ropt);
910
911         /* Mark which entries should be output */
912         ProcessArchiveRestoreOptions(fout);
913
914         /*
915          * The archive's TOC entries are now marked as to which ones will actually
916          * be output, so we can set up their dependency lists properly. This isn't
917          * necessary for plain-text output, though.
918          */
919         if (!plainText)
920                 BuildArchiveDependencies(fout);
921
922         /*
923          * And finally we can do the actual output.
924          *
925          * Note: for non-plain-text output formats, the output file is written
926          * inside CloseArchive().  This is, um, bizarre; but not worth changing
927          * right now.
928          */
929         if (plainText)
930                 RestoreArchive(fout);
931
932         CloseArchive(fout);
933
934         exit_nicely(0);
935 }
936
937
938 static void
939 help(const char *progname)
940 {
941         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
942         printf(_("Usage:\n"));
943         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
944
945         printf(_("\nGeneral options:\n"));
946         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
947         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
948                          "                               plain text (default))\n"));
949         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
950         printf(_("  -v, --verbose                verbose mode\n"));
951         printf(_("  -V, --version                output version information, then exit\n"));
952         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
953         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
954         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
955         printf(_("  -?, --help                   show this help, then exit\n"));
956
957         printf(_("\nOptions controlling the output content:\n"));
958         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
959         printf(_("  -b, --blobs                  include large objects in dump\n"));
960         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
961         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
962         printf(_("  -C, --create                 include commands to create database in dump\n"));
963         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
964         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
965         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
966         printf(_("  -o, --oids                   include OIDs in dump\n"));
967         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
968                          "                               plain-text format\n"));
969         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
970         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
971         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
972         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
973         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
974         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
975         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
976         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
977         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
978         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
979                          "                               access to)\n"));
980         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
981         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
982         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
983         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
984         printf(_("  --no-comments                do not dump comments\n"));
985         printf(_("  --no-publications            do not dump publications\n"));
986         printf(_("  --no-security-labels         do not dump security label assignments\n"));
987         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
988         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
989         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
990         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
991         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
992         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
993         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
994         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
995         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
996         printf(_("  --strict-names               require table and/or schema include patterns to\n"
997                          "                               match at least one entity each\n"));
998         printf(_("  --use-set-session-authorization\n"
999                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1000                          "                               ALTER OWNER commands to set ownership\n"));
1001
1002         printf(_("\nConnection options:\n"));
1003         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1004         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1005         printf(_("  -p, --port=PORT          database server port number\n"));
1006         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1007         printf(_("  -w, --no-password        never prompt for password\n"));
1008         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1009         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1010
1011         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1012                          "variable value is used.\n\n"));
1013         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1014 }
1015
1016 static void
1017 setup_connection(Archive *AH, const char *dumpencoding,
1018                                  const char *dumpsnapshot, char *use_role)
1019 {
1020         DumpOptions *dopt = AH->dopt;
1021         PGconn     *conn = GetConnection(AH);
1022         const char *std_strings;
1023
1024         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1025
1026         /*
1027          * Set the client encoding if requested.
1028          */
1029         if (dumpencoding)
1030         {
1031                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1032                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1033                                                   dumpencoding);
1034         }
1035
1036         /*
1037          * Get the active encoding and the standard_conforming_strings setting, so
1038          * we know how to escape strings.
1039          */
1040         AH->encoding = PQclientEncoding(conn);
1041
1042         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1043         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1044
1045         /*
1046          * Set the role if requested.  In a parallel dump worker, we'll be passed
1047          * use_role == NULL, but AH->use_role is already set (if user specified it
1048          * originally) and we should use that.
1049          */
1050         if (!use_role && AH->use_role)
1051                 use_role = AH->use_role;
1052
1053         /* Set the role if requested */
1054         if (use_role && AH->remoteVersion >= 80100)
1055         {
1056                 PQExpBuffer query = createPQExpBuffer();
1057
1058                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1059                 ExecuteSqlStatement(AH, query->data);
1060                 destroyPQExpBuffer(query);
1061
1062                 /* save it for possible later use by parallel workers */
1063                 if (!AH->use_role)
1064                         AH->use_role = pg_strdup(use_role);
1065         }
1066
1067         /* Set the datestyle to ISO to ensure the dump's portability */
1068         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1069
1070         /* Likewise, avoid using sql_standard intervalstyle */
1071         if (AH->remoteVersion >= 80400)
1072                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1073
1074         /*
1075          * Set extra_float_digits so that we can dump float data exactly (given
1076          * correctly implemented float I/O code, anyway)
1077          */
1078         if (AH->remoteVersion >= 90000)
1079                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1080         else
1081                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1082
1083         /*
1084          * If synchronized scanning is supported, disable it, to prevent
1085          * unpredictable changes in row ordering across a dump and reload.
1086          */
1087         if (AH->remoteVersion >= 80300)
1088                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1089
1090         /*
1091          * Disable timeouts if supported.
1092          */
1093         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1094         if (AH->remoteVersion >= 90300)
1095                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1096         if (AH->remoteVersion >= 90600)
1097                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1098
1099         /*
1100          * Quote all identifiers, if requested.
1101          */
1102         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1103                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1104
1105         /*
1106          * Adjust row-security mode, if supported.
1107          */
1108         if (AH->remoteVersion >= 90500)
1109         {
1110                 if (dopt->enable_row_security)
1111                         ExecuteSqlStatement(AH, "SET row_security = on");
1112                 else
1113                         ExecuteSqlStatement(AH, "SET row_security = off");
1114         }
1115
1116         /*
1117          * Start transaction-snapshot mode transaction to dump consistent data.
1118          */
1119         ExecuteSqlStatement(AH, "BEGIN");
1120         if (AH->remoteVersion >= 90100)
1121         {
1122                 /*
1123                  * To support the combination of serializable_deferrable with the jobs
1124                  * option we use REPEATABLE READ for the worker connections that are
1125                  * passed a snapshot.  As long as the snapshot is acquired in a
1126                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1127                  * REPEATABLE READ transaction provides the appropriate integrity
1128                  * guarantees.  This is a kluge, but safe for back-patching.
1129                  */
1130                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1131                         ExecuteSqlStatement(AH,
1132                                                                 "SET TRANSACTION ISOLATION LEVEL "
1133                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1134                 else
1135                         ExecuteSqlStatement(AH,
1136                                                                 "SET TRANSACTION ISOLATION LEVEL "
1137                                                                 "REPEATABLE READ, READ ONLY");
1138         }
1139         else
1140         {
1141                 ExecuteSqlStatement(AH,
1142                                                         "SET TRANSACTION ISOLATION LEVEL "
1143                                                         "SERIALIZABLE, READ ONLY");
1144         }
1145
1146         /*
1147          * If user specified a snapshot to use, select that.  In a parallel dump
1148          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1149          * is already set (if the server can handle it) and we should use that.
1150          */
1151         if (dumpsnapshot)
1152                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1153
1154         if (AH->sync_snapshot_id)
1155         {
1156                 PQExpBuffer query = createPQExpBuffer();
1157
1158                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1159                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1160                 ExecuteSqlStatement(AH, query->data);
1161                 destroyPQExpBuffer(query);
1162         }
1163         else if (AH->numWorkers > 1 &&
1164                          AH->remoteVersion >= 90200 &&
1165                          !dopt->no_synchronized_snapshots)
1166         {
1167                 if (AH->isStandby && AH->remoteVersion < 100000)
1168                         exit_horribly(NULL,
1169                                                   "Synchronized snapshots on standby servers are not supported by this server version.\n"
1170                                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1171                                                   "synchronized snapshots.\n");
1172
1173
1174                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1175         }
1176 }
1177
1178 /* Set up connection for a parallel worker process */
1179 static void
1180 setupDumpWorker(Archive *AH)
1181 {
1182         /*
1183          * We want to re-select all the same values the master connection is
1184          * using.  We'll have inherited directly-usable values in
1185          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1186          * inherited encoding value back to a string to pass to setup_connection.
1187          */
1188         setup_connection(AH,
1189                                          pg_encoding_to_char(AH->encoding),
1190                                          NULL,
1191                                          NULL);
1192 }
1193
1194 static char *
1195 get_synchronized_snapshot(Archive *fout)
1196 {
1197         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1198         char       *result;
1199         PGresult   *res;
1200
1201         res = ExecuteSqlQueryForSingleRow(fout, query);
1202         result = pg_strdup(PQgetvalue(res, 0, 0));
1203         PQclear(res);
1204
1205         return result;
1206 }
1207
1208 static ArchiveFormat
1209 parseArchiveFormat(const char *format, ArchiveMode *mode)
1210 {
1211         ArchiveFormat archiveFormat;
1212
1213         *mode = archModeWrite;
1214
1215         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1216         {
1217                 /* This is used by pg_dumpall, and is not documented */
1218                 archiveFormat = archNull;
1219                 *mode = archModeAppend;
1220         }
1221         else if (pg_strcasecmp(format, "c") == 0)
1222                 archiveFormat = archCustom;
1223         else if (pg_strcasecmp(format, "custom") == 0)
1224                 archiveFormat = archCustom;
1225         else if (pg_strcasecmp(format, "d") == 0)
1226                 archiveFormat = archDirectory;
1227         else if (pg_strcasecmp(format, "directory") == 0)
1228                 archiveFormat = archDirectory;
1229         else if (pg_strcasecmp(format, "p") == 0)
1230                 archiveFormat = archNull;
1231         else if (pg_strcasecmp(format, "plain") == 0)
1232                 archiveFormat = archNull;
1233         else if (pg_strcasecmp(format, "t") == 0)
1234                 archiveFormat = archTar;
1235         else if (pg_strcasecmp(format, "tar") == 0)
1236                 archiveFormat = archTar;
1237         else
1238                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1239         return archiveFormat;
1240 }
1241
1242 /*
1243  * Find the OIDs of all schemas matching the given list of patterns,
1244  * and append them to the given OID list.
1245  */
1246 static void
1247 expand_schema_name_patterns(Archive *fout,
1248                                                         SimpleStringList *patterns,
1249                                                         SimpleOidList *oids,
1250                                                         bool strict_names)
1251 {
1252         PQExpBuffer query;
1253         PGresult   *res;
1254         SimpleStringListCell *cell;
1255         int                     i;
1256
1257         if (patterns->head == NULL)
1258                 return;                                 /* nothing to do */
1259
1260         query = createPQExpBuffer();
1261
1262         /*
1263          * The loop below runs multiple SELECTs might sometimes result in
1264          * duplicate entries in the OID list, but we don't care.
1265          */
1266
1267         for (cell = patterns->head; cell; cell = cell->next)
1268         {
1269                 appendPQExpBuffer(query,
1270                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1271                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1272                                                           false, NULL, "n.nspname", NULL, NULL);
1273
1274                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1275                 if (strict_names && PQntuples(res) == 0)
1276                         exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1277
1278                 for (i = 0; i < PQntuples(res); i++)
1279                 {
1280                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1281                 }
1282
1283                 PQclear(res);
1284                 resetPQExpBuffer(query);
1285         }
1286
1287         destroyPQExpBuffer(query);
1288 }
1289
1290 /*
1291  * Find the OIDs of all tables matching the given list of patterns,
1292  * and append them to the given OID list.
1293  */
1294 static void
1295 expand_table_name_patterns(Archive *fout,
1296                                                    SimpleStringList *patterns, SimpleOidList *oids,
1297                                                    bool strict_names)
1298 {
1299         PQExpBuffer query;
1300         PGresult   *res;
1301         SimpleStringListCell *cell;
1302         int                     i;
1303
1304         if (patterns->head == NULL)
1305                 return;                                 /* nothing to do */
1306
1307         query = createPQExpBuffer();
1308
1309         /*
1310          * this might sometimes result in duplicate entries in the OID list, but
1311          * we don't care.
1312          */
1313
1314         for (cell = patterns->head; cell; cell = cell->next)
1315         {
1316                 /*
1317                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1318                  * would be unnecessary given a pg_table_is_visible() variant taking a
1319                  * search_path argument.
1320                  */
1321                 appendPQExpBuffer(query,
1322                                                   "SELECT c.oid"
1323                                                   "\nFROM pg_catalog.pg_class c"
1324                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1325                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1326                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1327                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1328                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1329                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1330                                                   RELKIND_PARTITIONED_TABLE);
1331                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1332                                                           false, "n.nspname", "c.relname", NULL,
1333                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1334
1335                 ExecuteSqlStatement(fout, "RESET search_path");
1336                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1337                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1338                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1339                 if (strict_names && PQntuples(res) == 0)
1340                         exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1341
1342                 for (i = 0; i < PQntuples(res); i++)
1343                 {
1344                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1345                 }
1346
1347                 PQclear(res);
1348                 resetPQExpBuffer(query);
1349         }
1350
1351         destroyPQExpBuffer(query);
1352 }
1353
1354 /*
1355  * checkExtensionMembership
1356  *              Determine whether object is an extension member, and if so,
1357  *              record an appropriate dependency and set the object's dump flag.
1358  *
1359  * It's important to call this for each object that could be an extension
1360  * member.  Generally, we integrate this with determining the object's
1361  * to-be-dumped-ness, since extension membership overrides other rules for that.
1362  *
1363  * Returns true if object is an extension member, else false.
1364  */
1365 static bool
1366 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1367 {
1368         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1369
1370         if (ext == NULL)
1371                 return false;
1372
1373         dobj->ext_member = true;
1374
1375         /* Record dependency so that getDependencies needn't deal with that */
1376         addObjectDependency(dobj, ext->dobj.dumpId);
1377
1378         /*
1379          * In 9.6 and above, mark the member object to have any non-initial ACL,
1380          * policies, and security labels dumped.
1381          *
1382          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1383          * extract the information about the object.  We don't provide support for
1384          * initial policies and security labels and it seems unlikely for those to
1385          * ever exist, but we may have to revisit this later.
1386          *
1387          * Prior to 9.6, we do not include any extension member components.
1388          *
1389          * In binary upgrades, we still dump all components of the members
1390          * individually, since the idea is to exactly reproduce the database
1391          * contents rather than replace the extension contents with something
1392          * different.
1393          */
1394         if (fout->dopt->binary_upgrade)
1395                 dobj->dump = ext->dobj.dump;
1396         else
1397         {
1398                 if (fout->remoteVersion < 90600)
1399                         dobj->dump = DUMP_COMPONENT_NONE;
1400                 else
1401                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1402                                                                                                         DUMP_COMPONENT_SECLABEL |
1403                                                                                                         DUMP_COMPONENT_POLICY);
1404         }
1405
1406         return true;
1407 }
1408
1409 /*
1410  * selectDumpableNamespace: policy-setting subroutine
1411  *              Mark a namespace as to be dumped or not
1412  */
1413 static void
1414 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1415 {
1416         /*
1417          * If specific tables are being dumped, do not dump any complete
1418          * namespaces. If specific namespaces are being dumped, dump just those
1419          * namespaces. Otherwise, dump all non-system namespaces.
1420          */
1421         if (table_include_oids.head != NULL)
1422                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1423         else if (schema_include_oids.head != NULL)
1424                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1425                         simple_oid_list_member(&schema_include_oids,
1426                                                                    nsinfo->dobj.catId.oid) ?
1427                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1428         else if (fout->remoteVersion >= 90600 &&
1429                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1430         {
1431                 /*
1432                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1433                  * they are interesting (and not the original ACLs which were set at
1434                  * initdb time, see pg_init_privs).
1435                  */
1436                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1437         }
1438         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1439                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1440         {
1441                 /* Other system schemas don't get dumped */
1442                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1443         }
1444         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1445         {
1446                 /*
1447                  * The public schema is a strange beast that sits in a sort of
1448                  * no-mans-land between being a system object and a user object.  We
1449                  * don't want to dump creation or comment commands for it, because
1450                  * that complicates matters for non-superuser use of pg_dump.  But we
1451                  * should dump any ACL changes that have occurred for it, and of
1452                  * course we should dump contained objects.
1453                  */
1454                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1455                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1456         }
1457         else
1458                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1459
1460         /*
1461          * In any case, a namespace can be excluded by an exclusion switch
1462          */
1463         if (nsinfo->dobj.dump_contains &&
1464                 simple_oid_list_member(&schema_exclude_oids,
1465                                                            nsinfo->dobj.catId.oid))
1466                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1467
1468         /*
1469          * If the schema belongs to an extension, allow extension membership to
1470          * override the dump decision for the schema itself.  However, this does
1471          * not change dump_contains, so this won't change what we do with objects
1472          * within the schema.  (If they belong to the extension, they'll get
1473          * suppressed by it, otherwise not.)
1474          */
1475         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1476 }
1477
1478 /*
1479  * selectDumpableTable: policy-setting subroutine
1480  *              Mark a table as to be dumped or not
1481  */
1482 static void
1483 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1484 {
1485         if (checkExtensionMembership(&tbinfo->dobj, fout))
1486                 return;                                 /* extension membership overrides all else */
1487
1488         /*
1489          * If specific tables are being dumped, dump just those tables; else, dump
1490          * according to the parent namespace's dump flag.
1491          */
1492         if (table_include_oids.head != NULL)
1493                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1494                                                                                                    tbinfo->dobj.catId.oid) ?
1495                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1496         else
1497                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1498
1499         /*
1500          * In any case, a table can be excluded by an exclusion switch
1501          */
1502         if (tbinfo->dobj.dump &&
1503                 simple_oid_list_member(&table_exclude_oids,
1504                                                            tbinfo->dobj.catId.oid))
1505                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1506 }
1507
1508 /*
1509  * selectDumpableType: policy-setting subroutine
1510  *              Mark a type as to be dumped or not
1511  *
1512  * If it's a table's rowtype or an autogenerated array type, we also apply a
1513  * special type code to facilitate sorting into the desired order.  (We don't
1514  * want to consider those to be ordinary types because that would bring tables
1515  * up into the datatype part of the dump order.)  We still set the object's
1516  * dump flag; that's not going to cause the dummy type to be dumped, but we
1517  * need it so that casts involving such types will be dumped correctly -- see
1518  * dumpCast.  This means the flag should be set the same as for the underlying
1519  * object (the table or base type).
1520  */
1521 static void
1522 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1523 {
1524         /* skip complex types, except for standalone composite types */
1525         if (OidIsValid(tyinfo->typrelid) &&
1526                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1527         {
1528                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1529
1530                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1531                 if (tytable != NULL)
1532                         tyinfo->dobj.dump = tytable->dobj.dump;
1533                 else
1534                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1535                 return;
1536         }
1537
1538         /* skip auto-generated array types */
1539         if (tyinfo->isArray)
1540         {
1541                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1542
1543                 /*
1544                  * Fall through to set the dump flag; we assume that the subsequent
1545                  * rules will do the same thing as they would for the array's base
1546                  * type.  (We cannot reliably look up the base type here, since
1547                  * getTypes may not have processed it yet.)
1548                  */
1549         }
1550
1551         if (checkExtensionMembership(&tyinfo->dobj, fout))
1552                 return;                                 /* extension membership overrides all else */
1553
1554         /* Dump based on if the contents of the namespace are being dumped */
1555         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1556 }
1557
1558 /*
1559  * selectDumpableDefaultACL: policy-setting subroutine
1560  *              Mark a default ACL as to be dumped or not
1561  *
1562  * For per-schema default ACLs, dump if the schema is to be dumped.
1563  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1564  * and aclsSkip are checked separately.
1565  */
1566 static void
1567 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1568 {
1569         /* Default ACLs can't be extension members */
1570
1571         if (dinfo->dobj.namespace)
1572                 /* default ACLs are considered part of the namespace */
1573                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1574         else
1575                 dinfo->dobj.dump = dopt->include_everything ?
1576                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1577 }
1578
1579 /*
1580  * selectDumpableCast: policy-setting subroutine
1581  *              Mark a cast as to be dumped or not
1582  *
1583  * Casts do not belong to any particular namespace (since they haven't got
1584  * names), nor do they have identifiable owners.  To distinguish user-defined
1585  * casts from built-in ones, we must resort to checking whether the cast's
1586  * OID is in the range reserved for initdb.
1587  */
1588 static void
1589 selectDumpableCast(CastInfo *cast, Archive *fout)
1590 {
1591         if (checkExtensionMembership(&cast->dobj, fout))
1592                 return;                                 /* extension membership overrides all else */
1593
1594         /*
1595          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1596          * support ACLs currently.
1597          */
1598         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1599                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1600         else
1601                 cast->dobj.dump = fout->dopt->include_everything ?
1602                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1603 }
1604
1605 /*
1606  * selectDumpableProcLang: policy-setting subroutine
1607  *              Mark a procedural language as to be dumped or not
1608  *
1609  * Procedural languages do not belong to any particular namespace.  To
1610  * identify built-in languages, we must resort to checking whether the
1611  * language's OID is in the range reserved for initdb.
1612  */
1613 static void
1614 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1615 {
1616         if (checkExtensionMembership(&plang->dobj, fout))
1617                 return;                                 /* extension membership overrides all else */
1618
1619         /*
1620          * Only include procedural languages when we are dumping everything.
1621          *
1622          * For from-initdb procedural languages, only include ACLs, as we do for
1623          * the pg_catalog namespace.  We need this because procedural languages do
1624          * not live in any namespace.
1625          */
1626         if (!fout->dopt->include_everything)
1627                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1628         else
1629         {
1630                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1631                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1632                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1633                 else
1634                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1635         }
1636 }
1637
1638 /*
1639  * selectDumpableAccessMethod: policy-setting subroutine
1640  *              Mark an access method as to be dumped or not
1641  *
1642  * Access methods do not belong to any particular namespace.  To identify
1643  * built-in access methods, we must resort to checking whether the
1644  * method's OID is in the range reserved for initdb.
1645  */
1646 static void
1647 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1648 {
1649         if (checkExtensionMembership(&method->dobj, fout))
1650                 return;                                 /* extension membership overrides all else */
1651
1652         /*
1653          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1654          * they do not support ACLs currently.
1655          */
1656         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1657                 method->dobj.dump = DUMP_COMPONENT_NONE;
1658         else
1659                 method->dobj.dump = fout->dopt->include_everything ?
1660                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1661 }
1662
1663 /*
1664  * selectDumpableExtension: policy-setting subroutine
1665  *              Mark an extension as to be dumped or not
1666  *
1667  * Built-in extensions should be skipped except for checking ACLs, since we
1668  * assume those will already be installed in the target database.  We identify
1669  * such extensions by their having OIDs in the range reserved for initdb.
1670  * We dump all user-added extensions by default, or none of them if
1671  * include_everything is false (i.e., a --schema or --table switch was given).
1672  */
1673 static void
1674 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1675 {
1676         /*
1677          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1678          * change permissions on their member objects, if they wish to, and have
1679          * those changes preserved.
1680          */
1681         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1682                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1683         else
1684                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1685                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1686                         DUMP_COMPONENT_NONE;
1687 }
1688
1689 /*
1690  * selectDumpablePublicationTable: policy-setting subroutine
1691  *              Mark a publication table as to be dumped or not
1692  *
1693  * Publication tables have schemas, but those are ignored in decision making,
1694  * because publications are only dumped when we are dumping everything.
1695  */
1696 static void
1697 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1698 {
1699         if (checkExtensionMembership(dobj, fout))
1700                 return;                                 /* extension membership overrides all else */
1701
1702         dobj->dump = fout->dopt->include_everything ?
1703                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1704 }
1705
1706 /*
1707  * selectDumpableObject: policy-setting subroutine
1708  *              Mark a generic dumpable object as to be dumped or not
1709  *
1710  * Use this only for object types without a special-case routine above.
1711  */
1712 static void
1713 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1714 {
1715         if (checkExtensionMembership(dobj, fout))
1716                 return;                                 /* extension membership overrides all else */
1717
1718         /*
1719          * Default policy is to dump if parent namespace is dumpable, or for
1720          * non-namespace-associated items, dump if we're dumping "everything".
1721          */
1722         if (dobj->namespace)
1723                 dobj->dump = dobj->namespace->dobj.dump_contains;
1724         else
1725                 dobj->dump = fout->dopt->include_everything ?
1726                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1727 }
1728
1729 /*
1730  *      Dump a table's contents for loading using the COPY command
1731  *      - this routine is called by the Archiver when it wants the table
1732  *        to be dumped.
1733  */
1734
1735 static int
1736 dumpTableData_copy(Archive *fout, void *dcontext)
1737 {
1738         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1739         TableInfo  *tbinfo = tdinfo->tdtable;
1740         const char *classname = tbinfo->dobj.name;
1741         const bool      hasoids = tbinfo->hasoids;
1742         const bool      oids = tdinfo->oids;
1743         PQExpBuffer q = createPQExpBuffer();
1744
1745         /*
1746          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1747          * which uses it already.
1748          */
1749         PQExpBuffer clistBuf = createPQExpBuffer();
1750         PGconn     *conn = GetConnection(fout);
1751         PGresult   *res;
1752         int                     ret;
1753         char       *copybuf;
1754         const char *column_list;
1755
1756         if (g_verbose)
1757                 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1758                                   tbinfo->dobj.namespace->dobj.name, classname);
1759
1760         /*
1761          * Specify the column list explicitly so that we have no possibility of
1762          * retrieving data in the wrong column order.  (The default column
1763          * ordering of COPY will not be what we want in certain corner cases
1764          * involving ADD COLUMN and inheritance.)
1765          */
1766         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1767
1768         if (oids && hasoids)
1769         {
1770                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1771                                                   fmtQualifiedDumpable(tbinfo),
1772                                                   column_list);
1773         }
1774         else if (tdinfo->filtercond)
1775         {
1776                 /* Note: this syntax is only supported in 8.2 and up */
1777                 appendPQExpBufferStr(q, "COPY (SELECT ");
1778                 /* klugery to get rid of parens in column list */
1779                 if (strlen(column_list) > 2)
1780                 {
1781                         appendPQExpBufferStr(q, column_list + 1);
1782                         q->data[q->len - 1] = ' ';
1783                 }
1784                 else
1785                         appendPQExpBufferStr(q, "* ");
1786                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1787                                                   fmtQualifiedDumpable(tbinfo),
1788                                                   tdinfo->filtercond);
1789         }
1790         else
1791         {
1792                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1793                                                   fmtQualifiedDumpable(tbinfo),
1794                                                   column_list);
1795         }
1796         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1797         PQclear(res);
1798         destroyPQExpBuffer(clistBuf);
1799
1800         for (;;)
1801         {
1802                 ret = PQgetCopyData(conn, &copybuf, 0);
1803
1804                 if (ret < 0)
1805                         break;                          /* done or error */
1806
1807                 if (copybuf)
1808                 {
1809                         WriteData(fout, copybuf, ret);
1810                         PQfreemem(copybuf);
1811                 }
1812
1813                 /* ----------
1814                  * THROTTLE:
1815                  *
1816                  * There was considerable discussion in late July, 2000 regarding
1817                  * slowing down pg_dump when backing up large tables. Users with both
1818                  * slow & fast (multi-processor) machines experienced performance
1819                  * degradation when doing a backup.
1820                  *
1821                  * Initial attempts based on sleeping for a number of ms for each ms
1822                  * of work were deemed too complex, then a simple 'sleep in each loop'
1823                  * implementation was suggested. The latter failed because the loop
1824                  * was too tight. Finally, the following was implemented:
1825                  *
1826                  * If throttle is non-zero, then
1827                  *              See how long since the last sleep.
1828                  *              Work out how long to sleep (based on ratio).
1829                  *              If sleep is more than 100ms, then
1830                  *                      sleep
1831                  *                      reset timer
1832                  *              EndIf
1833                  * EndIf
1834                  *
1835                  * where the throttle value was the number of ms to sleep per ms of
1836                  * work. The calculation was done in each loop.
1837                  *
1838                  * Most of the hard work is done in the backend, and this solution
1839                  * still did not work particularly well: on slow machines, the ratio
1840                  * was 50:1, and on medium paced machines, 1:1, and on fast
1841                  * multi-processor machines, it had little or no effect, for reasons
1842                  * that were unclear.
1843                  *
1844                  * Further discussion ensued, and the proposal was dropped.
1845                  *
1846                  * For those people who want this feature, it can be implemented using
1847                  * gettimeofday in each loop, calculating the time since last sleep,
1848                  * multiplying that by the sleep ratio, then if the result is more
1849                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1850                  * function to sleep for a subsecond period ie.
1851                  *
1852                  * select(0, NULL, NULL, NULL, &tvi);
1853                  *
1854                  * This will return after the interval specified in the structure tvi.
1855                  * Finally, call gettimeofday again to save the 'last sleep time'.
1856                  * ----------
1857                  */
1858         }
1859         archprintf(fout, "\\.\n\n\n");
1860
1861         if (ret == -2)
1862         {
1863                 /* copy data transfer failed */
1864                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1865                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1866                 write_msg(NULL, "The command was: %s\n", q->data);
1867                 exit_nicely(1);
1868         }
1869
1870         /* Check command status and return to normal libpq state */
1871         res = PQgetResult(conn);
1872         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1873         {
1874                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1875                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1876                 write_msg(NULL, "The command was: %s\n", q->data);
1877                 exit_nicely(1);
1878         }
1879         PQclear(res);
1880
1881         /* Do this to ensure we've pumped libpq back to idle state */
1882         if (PQgetResult(conn) != NULL)
1883                 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1884                                   classname);
1885
1886         destroyPQExpBuffer(q);
1887         return 1;
1888 }
1889
1890 /*
1891  * Dump table data using INSERT commands.
1892  *
1893  * Caution: when we restore from an archive file direct to database, the
1894  * INSERT commands emitted by this function have to be parsed by
1895  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1896  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1897  */
1898 static int
1899 dumpTableData_insert(Archive *fout, void *dcontext)
1900 {
1901         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1902         TableInfo  *tbinfo = tdinfo->tdtable;
1903         DumpOptions *dopt = fout->dopt;
1904         PQExpBuffer q = createPQExpBuffer();
1905         PQExpBuffer insertStmt = NULL;
1906         PGresult   *res;
1907         int                     tuple;
1908         int                     nfields;
1909         int                     field;
1910
1911         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1912                                           "SELECT * FROM ONLY %s",
1913                                           fmtQualifiedDumpable(tbinfo));
1914         if (tdinfo->filtercond)
1915                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1916
1917         ExecuteSqlStatement(fout, q->data);
1918
1919         while (1)
1920         {
1921                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1922                                                           PGRES_TUPLES_OK);
1923                 nfields = PQnfields(res);
1924                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1925                 {
1926                         /*
1927                          * First time through, we build as much of the INSERT statement as
1928                          * possible in "insertStmt", which we can then just print for each
1929                          * line. If the table happens to have zero columns then this will
1930                          * be a complete statement, otherwise it will end in "VALUES(" and
1931                          * be ready to have the row's column values appended.
1932                          */
1933                         if (insertStmt == NULL)
1934                         {
1935                                 TableInfo  *targettab;
1936
1937                                 insertStmt = createPQExpBuffer();
1938
1939                                 /*
1940                                  * When load-via-partition-root is set, get the root table
1941                                  * name for the partition table, so that we can reload data
1942                                  * through the root table.
1943                                  */
1944                                 if (dopt->load_via_partition_root && tbinfo->ispartition)
1945                                         targettab = getRootTableInfo(tbinfo);
1946                                 else
1947                                         targettab = tbinfo;
1948
1949                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1950                                                                   fmtQualifiedDumpable(targettab));
1951
1952                                 /* corner case for zero-column table */
1953                                 if (nfields == 0)
1954                                 {
1955                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1956                                 }
1957                                 else
1958                                 {
1959                                         /* append the list of column names if required */
1960                                         if (dopt->column_inserts)
1961                                         {
1962                                                 appendPQExpBufferChar(insertStmt, '(');
1963                                                 for (field = 0; field < nfields; field++)
1964                                                 {
1965                                                         if (field > 0)
1966                                                                 appendPQExpBufferStr(insertStmt, ", ");
1967                                                         appendPQExpBufferStr(insertStmt,
1968                                                                                                  fmtId(PQfname(res, field)));
1969                                                 }
1970                                                 appendPQExpBufferStr(insertStmt, ") ");
1971                                         }
1972
1973                                         if (tbinfo->needs_override)
1974                                                 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1975
1976                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1977                                 }
1978                         }
1979
1980                         archputs(insertStmt->data, fout);
1981
1982                         /* if it is zero-column table then we're done */
1983                         if (nfields == 0)
1984                                 continue;
1985
1986                         for (field = 0; field < nfields; field++)
1987                         {
1988                                 if (field > 0)
1989                                         archputs(", ", fout);
1990                                 if (PQgetisnull(res, tuple, field))
1991                                 {
1992                                         archputs("NULL", fout);
1993                                         continue;
1994                                 }
1995
1996                                 /* XXX This code is partially duplicated in ruleutils.c */
1997                                 switch (PQftype(res, field))
1998                                 {
1999                                         case INT2OID:
2000                                         case INT4OID:
2001                                         case INT8OID:
2002                                         case OIDOID:
2003                                         case FLOAT4OID:
2004                                         case FLOAT8OID:
2005                                         case NUMERICOID:
2006                                                 {
2007                                                         /*
2008                                                          * These types are printed without quotes unless
2009                                                          * they contain values that aren't accepted by the
2010                                                          * scanner unquoted (e.g., 'NaN').  Note that
2011                                                          * strtod() and friends might accept NaN, so we
2012                                                          * can't use that to test.
2013                                                          *
2014                                                          * In reality we only need to defend against
2015                                                          * infinity and NaN, so we need not get too crazy
2016                                                          * about pattern matching here.
2017                                                          */
2018                                                         const char *s = PQgetvalue(res, tuple, field);
2019
2020                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2021                                                                 archputs(s, fout);
2022                                                         else
2023                                                                 archprintf(fout, "'%s'", s);
2024                                                 }
2025                                                 break;
2026
2027                                         case BITOID:
2028                                         case VARBITOID:
2029                                                 archprintf(fout, "B'%s'",
2030                                                                    PQgetvalue(res, tuple, field));
2031                                                 break;
2032
2033                                         case BOOLOID:
2034                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2035                                                         archputs("true", fout);
2036                                                 else
2037                                                         archputs("false", fout);
2038                                                 break;
2039
2040                                         default:
2041                                                 /* All other types are printed as string literals. */
2042                                                 resetPQExpBuffer(q);
2043                                                 appendStringLiteralAH(q,
2044                                                                                           PQgetvalue(res, tuple, field),
2045                                                                                           fout);
2046                                                 archputs(q->data, fout);
2047                                                 break;
2048                                 }
2049                         }
2050
2051                         if (!dopt->do_nothing)
2052                                 archputs(");\n", fout);
2053                         else
2054                                 archputs(") ON CONFLICT DO NOTHING;\n", fout);
2055                 }
2056
2057                 if (PQntuples(res) <= 0)
2058                 {
2059                         PQclear(res);
2060                         break;
2061                 }
2062                 PQclear(res);
2063         }
2064
2065         archputs("\n\n", fout);
2066
2067         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2068
2069         destroyPQExpBuffer(q);
2070         if (insertStmt != NULL)
2071                 destroyPQExpBuffer(insertStmt);
2072
2073         return 1;
2074 }
2075
2076 /*
2077  * getRootTableInfo:
2078  *     get the root TableInfo for the given partition table.
2079  */
2080 static TableInfo *
2081 getRootTableInfo(TableInfo *tbinfo)
2082 {
2083         TableInfo  *parentTbinfo;
2084
2085         Assert(tbinfo->ispartition);
2086         Assert(tbinfo->numParents == 1);
2087
2088         parentTbinfo = tbinfo->parents[0];
2089         while (parentTbinfo->ispartition)
2090         {
2091                 Assert(parentTbinfo->numParents == 1);
2092                 parentTbinfo = parentTbinfo->parents[0];
2093         }
2094
2095         return parentTbinfo;
2096 }
2097
2098 /*
2099  * dumpTableData -
2100  *        dump the contents of a single table
2101  *
2102  * Actually, this just makes an ArchiveEntry for the table contents.
2103  */
2104 static void
2105 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2106 {
2107         DumpOptions *dopt = fout->dopt;
2108         TableInfo  *tbinfo = tdinfo->tdtable;
2109         PQExpBuffer copyBuf = createPQExpBuffer();
2110         PQExpBuffer clistBuf = createPQExpBuffer();
2111         DataDumperPtr dumpFn;
2112         char       *copyStmt;
2113         const char *copyFrom;
2114
2115         if (!dopt->dump_inserts)
2116         {
2117                 /* Dump/restore using COPY */
2118                 dumpFn = dumpTableData_copy;
2119
2120                 /*
2121                  * When load-via-partition-root is set, get the root table name for
2122                  * the partition table, so that we can reload data through the root
2123                  * table.
2124                  */
2125                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2126                 {
2127                         TableInfo  *parentTbinfo;
2128
2129                         parentTbinfo = getRootTableInfo(tbinfo);
2130                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2131                 }
2132                 else
2133                         copyFrom = fmtQualifiedDumpable(tbinfo);
2134
2135                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2136                 appendPQExpBuffer(copyBuf, "COPY %s ",
2137                                                   copyFrom);
2138                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
2139                                                   fmtCopyColumnList(tbinfo, clistBuf),
2140                                                   (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
2141                 copyStmt = copyBuf->data;
2142         }
2143         else
2144         {
2145                 /* Restore using INSERT */
2146                 dumpFn = dumpTableData_insert;
2147                 copyStmt = NULL;
2148         }
2149
2150         /*
2151          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2152          * dependency on its table as "special" and pass it to ArchiveEntry now.
2153          * See comments for BuildArchiveDependencies.
2154          */
2155         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2156         {
2157                 TocEntry   *te;
2158
2159                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2160                                                   tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2161                                                   NULL, tbinfo->rolname,
2162                                                   false, "TABLE DATA", SECTION_DATA,
2163                                                   "", "", copyStmt,
2164                                                   &(tbinfo->dobj.dumpId), 1,
2165                                                   dumpFn, tdinfo);
2166
2167                 /*
2168                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2169                  * and want to order dump jobs by table size.  We choose to measure
2170                  * dataLength in table pages during dump, so no scaling is needed.
2171                  * However, relpages is declared as "integer" in pg_class, and hence
2172                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2173                  * Cast so that we get the right interpretation of table sizes
2174                  * exceeding INT_MAX pages.
2175                  */
2176                 te->dataLength = (BlockNumber) tbinfo->relpages;
2177         }
2178
2179         destroyPQExpBuffer(copyBuf);
2180         destroyPQExpBuffer(clistBuf);
2181 }
2182
2183 /*
2184  * refreshMatViewData -
2185  *        load or refresh the contents of a single materialized view
2186  *
2187  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2188  * statement.
2189  */
2190 static void
2191 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2192 {
2193         TableInfo  *tbinfo = tdinfo->tdtable;
2194         PQExpBuffer q;
2195
2196         /* If the materialized view is not flagged as populated, skip this. */
2197         if (!tbinfo->relispopulated)
2198                 return;
2199
2200         q = createPQExpBuffer();
2201
2202         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2203                                           fmtQualifiedDumpable(tbinfo));
2204
2205         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2206                 ArchiveEntry(fout,
2207                                          tdinfo->dobj.catId,    /* catalog ID */
2208                                          tdinfo->dobj.dumpId,   /* dump ID */
2209                                          tbinfo->dobj.name, /* Name */
2210                                          tbinfo->dobj.namespace->dobj.name, /* Namespace */
2211                                          NULL,          /* Tablespace */
2212                                          tbinfo->rolname,       /* Owner */
2213                                          false,         /* with oids */
2214                                          "MATERIALIZED VIEW DATA",      /* Desc */
2215                                          SECTION_POST_DATA, /* Section */
2216                                          q->data,       /* Create */
2217                                          "",            /* Del */
2218                                          NULL,          /* Copy */
2219                                          tdinfo->dobj.dependencies, /* Deps */
2220                                          tdinfo->dobj.nDeps,    /* # Deps */
2221                                          NULL,          /* Dumper */
2222                                          NULL);         /* Dumper Arg */
2223
2224         destroyPQExpBuffer(q);
2225 }
2226
2227 /*
2228  * getTableData -
2229  *        set up dumpable objects representing the contents of tables
2230  */
2231 static void
2232 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind)
2233 {
2234         int                     i;
2235
2236         for (i = 0; i < numTables; i++)
2237         {
2238                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2239                         (!relkind || tblinfo[i].relkind == relkind))
2240                         makeTableDataInfo(dopt, &(tblinfo[i]), oids);
2241         }
2242 }
2243
2244 /*
2245  * Make a dumpable object for the data of this specific table
2246  *
2247  * Note: we make a TableDataInfo if and only if we are going to dump the
2248  * table data; the "dump" flag in such objects isn't used.
2249  */
2250 static void
2251 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
2252 {
2253         TableDataInfo *tdinfo;
2254
2255         /*
2256          * Nothing to do if we already decided to dump the table.  This will
2257          * happen for "config" tables.
2258          */
2259         if (tbinfo->dataObj != NULL)
2260                 return;
2261
2262         /* Skip VIEWs (no data to dump) */
2263         if (tbinfo->relkind == RELKIND_VIEW)
2264                 return;
2265         /* Skip FOREIGN TABLEs (no data to dump) */
2266         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2267                 return;
2268         /* Skip partitioned tables (data in partitions) */
2269         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2270                 return;
2271
2272         /* Don't dump data in unlogged tables, if so requested */
2273         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2274                 dopt->no_unlogged_table_data)
2275                 return;
2276
2277         /* Check that the data is not explicitly excluded */
2278         if (simple_oid_list_member(&tabledata_exclude_oids,
2279                                                            tbinfo->dobj.catId.oid))
2280                 return;
2281
2282         /* OK, let's dump it */
2283         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2284
2285         if (tbinfo->relkind == RELKIND_MATVIEW)
2286                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2287         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2288                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2289         else
2290                 tdinfo->dobj.objType = DO_TABLE_DATA;
2291
2292         /*
2293          * Note: use tableoid 0 so that this object won't be mistaken for
2294          * something that pg_depend entries apply to.
2295          */
2296         tdinfo->dobj.catId.tableoid = 0;
2297         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2298         AssignDumpId(&tdinfo->dobj);
2299         tdinfo->dobj.name = tbinfo->dobj.name;
2300         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2301         tdinfo->tdtable = tbinfo;
2302         tdinfo->oids = oids;
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                                  datname,               /* Name */
2750                                  NULL,                  /* Namespace */
2751                                  NULL,                  /* Tablespace */
2752                                  dba,                   /* Owner */
2753                                  false,                 /* with oids */
2754                                  "DATABASE",    /* Desc */
2755                                  SECTION_PRE_DATA,      /* Section */
2756                                  creaQry->data, /* Create */
2757                                  delQry->data,  /* Del */
2758                                  NULL,                  /* Copy */
2759                                  NULL,                  /* Deps */
2760                                  0,                             /* # Deps */
2761                                  NULL,                  /* Dumper */
2762                                  NULL);                 /* Dumper Arg */
2763
2764         /* Compute correct tag for archive entry */
2765         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2766
2767         /* Dump DB comment if any */
2768         if (fout->remoteVersion >= 80200)
2769         {
2770                 /*
2771                  * 8.2 and up keep comments on shared objects in a shared table, so we
2772                  * cannot use the dumpComment() code used for other database objects.
2773                  * Be careful that the ArchiveEntry parameters match that function.
2774                  */
2775                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2776
2777                 if (comment && *comment && !dopt->no_comments)
2778                 {
2779                         resetPQExpBuffer(dbQry);
2780
2781                         /*
2782                          * Generates warning when loaded into a differently-named
2783                          * database.
2784                          */
2785                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2786                         appendStringLiteralAH(dbQry, comment, fout);
2787                         appendPQExpBufferStr(dbQry, ";\n");
2788
2789                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2790                                                  labelq->data, NULL, NULL, dba,
2791                                                  false, "COMMENT", SECTION_NONE,
2792                                                  dbQry->data, "", NULL,
2793                                                  &(dbDumpId), 1,
2794                                                  NULL, NULL);
2795                 }
2796         }
2797         else
2798         {
2799                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2800                                         dbCatId, 0, dbDumpId);
2801         }
2802
2803         /* Dump DB security label, if enabled */
2804         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2805         {
2806                 PGresult   *shres;
2807                 PQExpBuffer seclabelQry;
2808
2809                 seclabelQry = createPQExpBuffer();
2810
2811                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2812                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2813                 resetPQExpBuffer(seclabelQry);
2814                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2815                 if (seclabelQry->len > 0)
2816                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2817                                                  labelq->data, NULL, NULL, dba,
2818                                                  false, "SECURITY LABEL", SECTION_NONE,
2819                                                  seclabelQry->data, "", NULL,
2820                                                  &(dbDumpId), 1,
2821                                                  NULL, NULL);
2822                 destroyPQExpBuffer(seclabelQry);
2823                 PQclear(shres);
2824         }
2825
2826         /*
2827          * Dump ACL if any.  Note that we do not support initial privileges
2828          * (pg_init_privs) on databases.
2829          */
2830         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2831                         qdatname, NULL, NULL,
2832                         dba, datacl, rdatacl, "", "");
2833
2834         /*
2835          * Now construct a DATABASE PROPERTIES archive entry to restore any
2836          * non-default database-level properties.  (The reason this must be
2837          * separate is that we cannot put any additional commands into the TOC
2838          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2839          * in an implicit transaction block, and the backend won't allow CREATE
2840          * DATABASE in that context.)
2841          */
2842         resetPQExpBuffer(creaQry);
2843         resetPQExpBuffer(delQry);
2844
2845         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2846                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2847                                                   qdatname, datconnlimit);
2848
2849         if (strcmp(datistemplate, "t") == 0)
2850         {
2851                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2852                                                   qdatname);
2853
2854                 /*
2855                  * The backend won't accept DROP DATABASE on a template database.  We
2856                  * can deal with that by removing the template marking before the DROP
2857                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2858                  * since no such command is currently supported, fake it with a direct
2859                  * UPDATE on pg_database.
2860                  */
2861                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2862                                                          "SET datistemplate = false WHERE datname = ");
2863                 appendStringLiteralAH(delQry, datname, fout);
2864                 appendPQExpBufferStr(delQry, ";\n");
2865         }
2866
2867         /* Add database-specific SET options */
2868         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2869
2870         /*
2871          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2872          * entry, too, for lack of a better place.
2873          */
2874         if (dopt->binary_upgrade)
2875         {
2876                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2877                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2878                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2879                                                   "WHERE datname = ",
2880                                                   frozenxid, minmxid);
2881                 appendStringLiteralAH(creaQry, datname, fout);
2882                 appendPQExpBufferStr(creaQry, ";\n");
2883         }
2884
2885         if (creaQry->len > 0)
2886                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2887                                          datname, NULL, NULL, dba,
2888                                          false, "DATABASE PROPERTIES", SECTION_PRE_DATA,
2889                                          creaQry->data, delQry->data, NULL,
2890                                          &(dbDumpId), 1,
2891                                          NULL, NULL);
2892
2893         /*
2894          * pg_largeobject and pg_largeobject_metadata come from the old system
2895          * intact, so set their relfrozenxids and relminmxids.
2896          */
2897         if (dopt->binary_upgrade)
2898         {
2899                 PGresult   *lo_res;
2900                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2901                 PQExpBuffer loOutQry = createPQExpBuffer();
2902                 int                     i_relfrozenxid,
2903                                         i_relminmxid;
2904
2905                 /*
2906                  * pg_largeobject
2907                  */
2908                 if (fout->remoteVersion >= 90300)
2909                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2910                                                           "FROM pg_catalog.pg_class\n"
2911                                                           "WHERE oid = %u;\n",
2912                                                           LargeObjectRelationId);
2913                 else
2914                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2915                                                           "FROM pg_catalog.pg_class\n"
2916                                                           "WHERE oid = %u;\n",
2917                                                           LargeObjectRelationId);
2918
2919                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2920
2921                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2922                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2923
2924                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2925                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2926                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2927                                                   "WHERE oid = %u;\n",
2928                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2929                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2930                                                   LargeObjectRelationId);
2931                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2932                                          "pg_largeobject", NULL, NULL, "",
2933                                          false, "pg_largeobject", SECTION_PRE_DATA,
2934                                          loOutQry->data, "", NULL,
2935                                          NULL, 0,
2936                                          NULL, NULL);
2937
2938                 PQclear(lo_res);
2939
2940                 /*
2941                  * pg_largeobject_metadata
2942                  */
2943                 if (fout->remoteVersion >= 90000)
2944                 {
2945                         resetPQExpBuffer(loFrozenQry);
2946                         resetPQExpBuffer(loOutQry);
2947
2948                         if (fout->remoteVersion >= 90300)
2949                                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2950                                                                   "FROM pg_catalog.pg_class\n"
2951                                                                   "WHERE oid = %u;\n",
2952                                                                   LargeObjectMetadataRelationId);
2953                         else
2954                                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2955                                                                   "FROM pg_catalog.pg_class\n"
2956                                                                   "WHERE oid = %u;\n",
2957                                                                   LargeObjectMetadataRelationId);
2958
2959                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2960
2961                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2962                         i_relminmxid = PQfnumber(lo_res, "relminmxid");
2963
2964                         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2965                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2966                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2967                                                           "WHERE oid = %u;\n",
2968                                                           atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2969                                                           atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2970                                                           LargeObjectMetadataRelationId);
2971                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2972                                                  "pg_largeobject_metadata", NULL, NULL, "",
2973                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2974                                                  loOutQry->data, "", NULL,
2975                                                  NULL, 0,
2976                                                  NULL, NULL);
2977
2978                         PQclear(lo_res);
2979                 }
2980
2981                 destroyPQExpBuffer(loFrozenQry);
2982                 destroyPQExpBuffer(loOutQry);
2983         }
2984
2985         PQclear(res);
2986
2987         free(qdatname);
2988         destroyPQExpBuffer(dbQry);
2989         destroyPQExpBuffer(delQry);
2990         destroyPQExpBuffer(creaQry);
2991         destroyPQExpBuffer(labelq);
2992 }
2993
2994 /*
2995  * Collect any database-specific or role-and-database-specific SET options
2996  * for this database, and append them to outbuf.
2997  */
2998 static void
2999 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3000                                    const char *dbname, Oid dboid)
3001 {
3002         PGconn     *conn = GetConnection(AH);
3003         PQExpBuffer buf = createPQExpBuffer();
3004         PGresult   *res;
3005         int                     count = 1;
3006
3007         /*
3008          * First collect database-specific options.  Pre-8.4 server versions lack
3009          * unnest(), so we do this the hard way by querying once per subscript.
3010          */
3011         for (;;)
3012         {
3013                 if (AH->remoteVersion >= 90000)
3014                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3015                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3016                                                           count, dboid);
3017                 else
3018                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3019
3020                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3021
3022                 if (PQntuples(res) == 1 &&
3023                         !PQgetisnull(res, 0, 0))
3024                 {
3025                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3026                                                                    "DATABASE", dbname, NULL, NULL,
3027                                                                    outbuf);
3028                         PQclear(res);
3029                         count++;
3030                 }
3031                 else
3032                 {
3033                         PQclear(res);
3034                         break;
3035                 }
3036         }
3037
3038         /* Now look for role-and-database-specific options */
3039         if (AH->remoteVersion >= 90000)
3040         {
3041                 /* Here we can assume we have unnest() */
3042                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3043                                                   "FROM pg_db_role_setting s, pg_roles r "
3044                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3045                                                   dboid);
3046
3047                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3048
3049                 if (PQntuples(res) > 0)
3050                 {
3051                         int                     i;
3052
3053                         for (i = 0; i < PQntuples(res); i++)
3054                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3055                                                                            "ROLE", PQgetvalue(res, i, 0),
3056                                                                            "DATABASE", dbname,
3057                                                                            outbuf);
3058                 }
3059
3060                 PQclear(res);
3061         }
3062
3063         destroyPQExpBuffer(buf);
3064 }
3065
3066 /*
3067  * dumpEncoding: put the correct encoding into the archive
3068  */
3069 static void
3070 dumpEncoding(Archive *AH)
3071 {
3072         const char *encname = pg_encoding_to_char(AH->encoding);
3073         PQExpBuffer qry = createPQExpBuffer();
3074
3075         if (g_verbose)
3076                 write_msg(NULL, "saving encoding = %s\n", encname);
3077
3078         appendPQExpBufferStr(qry, "SET client_encoding = ");
3079         appendStringLiteralAH(qry, encname, AH);
3080         appendPQExpBufferStr(qry, ";\n");
3081
3082         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3083                                  "ENCODING", NULL, NULL, "",
3084                                  false, "ENCODING", SECTION_PRE_DATA,
3085                                  qry->data, "", NULL,
3086                                  NULL, 0,
3087                                  NULL, NULL);
3088
3089         destroyPQExpBuffer(qry);
3090 }
3091
3092
3093 /*
3094  * dumpStdStrings: put the correct escape string behavior into the archive
3095  */
3096 static void
3097 dumpStdStrings(Archive *AH)
3098 {
3099         const char *stdstrings = AH->std_strings ? "on" : "off";
3100         PQExpBuffer qry = createPQExpBuffer();
3101
3102         if (g_verbose)
3103                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3104                                   stdstrings);
3105
3106         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3107                                           stdstrings);
3108
3109         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3110                                  "STDSTRINGS", NULL, NULL, "",
3111                                  false, "STDSTRINGS", SECTION_PRE_DATA,
3112                                  qry->data, "", NULL,
3113                                  NULL, 0,
3114                                  NULL, NULL);
3115
3116         destroyPQExpBuffer(qry);
3117 }
3118
3119 /*
3120  * dumpSearchPath: record the active search_path in the archive
3121  */
3122 static void
3123 dumpSearchPath(Archive *AH)
3124 {
3125         PQExpBuffer qry = createPQExpBuffer();
3126         PQExpBuffer path = createPQExpBuffer();
3127         PGresult   *res;
3128         char      **schemanames = NULL;
3129         int                     nschemanames = 0;
3130         int                     i;
3131
3132         /*
3133          * We use the result of current_schemas(), not the search_path GUC,
3134          * because that might contain wildcards such as "$user", which won't
3135          * necessarily have the same value during restore.  Also, this way avoids
3136          * listing schemas that may appear in search_path but not actually exist,
3137          * which seems like a prudent exclusion.
3138          */
3139         res = ExecuteSqlQueryForSingleRow(AH,
3140                                                                           "SELECT pg_catalog.current_schemas(false)");
3141
3142         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3143                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3144
3145         /*
3146          * We use set_config(), not a simple "SET search_path" command, because
3147          * the latter has less-clean behavior if the search path is empty.  While
3148          * that's likely to get fixed at some point, it seems like a good idea to
3149          * be as backwards-compatible as possible in what we put into archives.
3150          */
3151         for (i = 0; i < nschemanames; i++)
3152         {
3153                 if (i > 0)
3154                         appendPQExpBufferStr(path, ", ");
3155                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3156         }
3157
3158         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3159         appendStringLiteralAH(qry, path->data, AH);
3160         appendPQExpBufferStr(qry, ", false);\n");
3161
3162         if (g_verbose)
3163                 write_msg(NULL, "saving search_path = %s\n", path->data);
3164
3165         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3166                                  "SEARCHPATH", NULL, NULL, "",
3167                                  false, "SEARCHPATH", SECTION_PRE_DATA,
3168                                  qry->data, "", NULL,
3169                                  NULL, 0,
3170                                  NULL, NULL);
3171
3172         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3173         AH->searchpath = pg_strdup(qry->data);
3174
3175         if (schemanames)
3176                 free(schemanames);
3177         PQclear(res);
3178         destroyPQExpBuffer(qry);
3179         destroyPQExpBuffer(path);
3180 }
3181
3182
3183 /*
3184  * getBlobs:
3185  *      Collect schema-level data about large objects
3186  */
3187 static void
3188 getBlobs(Archive *fout)
3189 {
3190         DumpOptions *dopt = fout->dopt;
3191         PQExpBuffer blobQry = createPQExpBuffer();
3192         BlobInfo   *binfo;
3193         DumpableObject *bdata;
3194         PGresult   *res;
3195         int                     ntups;
3196         int                     i;
3197         int                     i_oid;
3198         int                     i_lomowner;
3199         int                     i_lomacl;
3200         int                     i_rlomacl;
3201         int                     i_initlomacl;
3202         int                     i_initrlomacl;
3203
3204         /* Verbose message */
3205         if (g_verbose)
3206                 write_msg(NULL, "reading large objects\n");
3207
3208         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3209         if (fout->remoteVersion >= 90600)
3210         {
3211                 PQExpBuffer acl_subquery = createPQExpBuffer();
3212                 PQExpBuffer racl_subquery = createPQExpBuffer();
3213                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3214                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3215
3216                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3217                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3218                                                 dopt->binary_upgrade);
3219
3220                 appendPQExpBuffer(blobQry,
3221                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3222                                                   "%s AS lomacl, "
3223                                                   "%s AS rlomacl, "
3224                                                   "%s AS initlomacl, "
3225                                                   "%s AS initrlomacl "
3226                                                   "FROM pg_largeobject_metadata l "
3227                                                   "LEFT JOIN pg_init_privs pip ON "
3228                                                   "(l.oid = pip.objoid "
3229                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3230                                                   "AND pip.objsubid = 0) ",
3231                                                   username_subquery,
3232                                                   acl_subquery->data,
3233                                                   racl_subquery->data,
3234                                                   init_acl_subquery->data,
3235                                                   init_racl_subquery->data);
3236
3237                 destroyPQExpBuffer(acl_subquery);
3238                 destroyPQExpBuffer(racl_subquery);
3239                 destroyPQExpBuffer(init_acl_subquery);
3240                 destroyPQExpBuffer(init_racl_subquery);
3241         }
3242         else if (fout->remoteVersion >= 90000)
3243                 appendPQExpBuffer(blobQry,
3244                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3245                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3246                                                   "NULL AS initrlomacl "
3247                                                   " FROM pg_largeobject_metadata",
3248                                                   username_subquery);
3249         else
3250                 appendPQExpBufferStr(blobQry,
3251                                                          "SELECT DISTINCT loid AS oid, "
3252                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3253                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3254                                                          "NULL::oid AS initrlomacl "
3255                                                          " FROM pg_largeobject");
3256
3257         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3258
3259         i_oid = PQfnumber(res, "oid");
3260         i_lomowner = PQfnumber(res, "rolname");
3261         i_lomacl = PQfnumber(res, "lomacl");
3262         i_rlomacl = PQfnumber(res, "rlomacl");
3263         i_initlomacl = PQfnumber(res, "initlomacl");
3264         i_initrlomacl = PQfnumber(res, "initrlomacl");
3265
3266         ntups = PQntuples(res);
3267
3268         /*
3269          * Each large object has its own BLOB archive entry.
3270          */
3271         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3272
3273         for (i = 0; i < ntups; i++)
3274         {
3275                 binfo[i].dobj.objType = DO_BLOB;
3276                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3277                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3278                 AssignDumpId(&binfo[i].dobj);
3279
3280                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3281                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3282                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3283                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3284                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3285                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3286
3287                 if (PQgetisnull(res, i, i_lomacl) &&
3288                         PQgetisnull(res, i, i_rlomacl) &&
3289                         PQgetisnull(res, i, i_initlomacl) &&
3290                         PQgetisnull(res, i, i_initrlomacl))
3291                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3292
3293                 /*
3294                  * In binary-upgrade mode for blobs, we do *not* dump out the data or
3295                  * the ACLs, should any exist.  The data and ACL (if any) will be
3296                  * copied by pg_upgrade, which simply copies the pg_largeobject and
3297                  * pg_largeobject_metadata tables.
3298                  *
3299                  * We *do* dump out the definition of the blob because we need that to
3300                  * make the restoration of the comments, and anything else, work since
3301                  * pg_upgrade copies the files behind pg_largeobject and
3302                  * pg_largeobject_metadata after the dump is restored.
3303                  */
3304                 if (dopt->binary_upgrade)
3305                         binfo[i].dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL);
3306         }
3307
3308         /*
3309          * If we have any large objects, a "BLOBS" archive entry is needed. This
3310          * is just a placeholder for sorting; it carries no data now.
3311          */
3312         if (ntups > 0)
3313         {
3314                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3315                 bdata->objType = DO_BLOB_DATA;
3316                 bdata->catId = nilCatalogId;
3317                 AssignDumpId(bdata);
3318                 bdata->name = pg_strdup("BLOBS");
3319         }
3320
3321         PQclear(res);
3322         destroyPQExpBuffer(blobQry);
3323 }
3324
3325 /*
3326  * dumpBlob
3327  *
3328  * dump the definition (metadata) of the given large object
3329  */
3330 static void
3331 dumpBlob(Archive *fout, BlobInfo *binfo)
3332 {
3333         PQExpBuffer cquery = createPQExpBuffer();
3334         PQExpBuffer dquery = createPQExpBuffer();
3335
3336         appendPQExpBuffer(cquery,
3337                                           "SELECT pg_catalog.lo_create('%s');\n",
3338                                           binfo->dobj.name);
3339
3340         appendPQExpBuffer(dquery,
3341                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3342                                           binfo->dobj.name);
3343
3344         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3345                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3346                                          binfo->dobj.name,
3347                                          NULL, NULL,
3348                                          binfo->rolname, false,
3349                                          "BLOB", SECTION_PRE_DATA,
3350                                          cquery->data, dquery->data, NULL,
3351                                          NULL, 0,
3352                                          NULL, NULL);
3353
3354         /* Dump comment if any */
3355         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3356                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3357                                         NULL, binfo->rolname,
3358                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3359
3360         /* Dump security label if any */
3361         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3362                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3363                                          NULL, binfo->rolname,
3364                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3365
3366         /* Dump ACL if any */
3367         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3368                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3369                                 binfo->dobj.name, NULL,
3370                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3371                                 binfo->initblobacl, binfo->initrblobacl);
3372
3373         destroyPQExpBuffer(cquery);
3374         destroyPQExpBuffer(dquery);
3375 }
3376
3377 /*
3378  * dumpBlobs:
3379  *      dump the data contents of all large objects
3380  */
3381 static int
3382 dumpBlobs(Archive *fout, void *arg)
3383 {
3384         const char *blobQry;
3385         const char *blobFetchQry;
3386         PGconn     *conn = GetConnection(fout);
3387         PGresult   *res;
3388         char            buf[LOBBUFSIZE];
3389         int                     ntups;
3390         int                     i;
3391         int                     cnt;
3392
3393         if (g_verbose)
3394                 write_msg(NULL, "saving large objects\n");
3395
3396         /*
3397          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3398          * the already-in-memory dumpable objects instead...
3399          */
3400         if (fout->remoteVersion >= 90000)
3401                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
3402         else
3403                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
3404
3405         ExecuteSqlStatement(fout, blobQry);
3406
3407         /* Command to fetch from cursor */
3408         blobFetchQry = "FETCH 1000 IN bloboid";
3409
3410         do
3411         {
3412                 /* Do a fetch */
3413                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3414
3415                 /* Process the tuples, if any */
3416                 ntups = PQntuples(res);
3417                 for (i = 0; i < ntups; i++)
3418                 {
3419                         Oid                     blobOid;
3420                         int                     loFd;
3421
3422                         blobOid = atooid(PQgetvalue(res, i, 0));
3423                         /* Open the BLOB */
3424                         loFd = lo_open(conn, blobOid, INV_READ);
3425                         if (loFd == -1)
3426                                 exit_horribly(NULL, "could not open large object %u: %s",
3427                                                           blobOid, PQerrorMessage(conn));
3428
3429                         StartBlob(fout, blobOid);
3430
3431                         /* Now read it in chunks, sending data to archive */
3432                         do
3433                         {
3434                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3435                                 if (cnt < 0)
3436                                         exit_horribly(NULL, "error reading large object %u: %s",
3437                                                                   blobOid, PQerrorMessage(conn));
3438
3439                                 WriteData(fout, buf, cnt);
3440                         } while (cnt > 0);
3441
3442                         lo_close(conn, loFd);
3443
3444                         EndBlob(fout, blobOid);
3445                 }
3446
3447                 PQclear(res);
3448         } while (ntups > 0);
3449
3450         return 1;
3451 }
3452
3453 /*
3454  * getPolicies
3455  *        get information about policies on a dumpable table.
3456  */
3457 void
3458 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3459 {
3460         PQExpBuffer query;
3461         PGresult   *res;
3462         PolicyInfo *polinfo;
3463         int                     i_oid;
3464         int                     i_tableoid;
3465         int                     i_polname;
3466         int                     i_polcmd;
3467         int                     i_polpermissive;
3468         int                     i_polroles;
3469         int                     i_polqual;
3470         int                     i_polwithcheck;
3471         int                     i,
3472                                 j,
3473                                 ntups;
3474
3475         if (fout->remoteVersion < 90500)
3476                 return;
3477
3478         query = createPQExpBuffer();
3479
3480         for (i = 0; i < numTables; i++)
3481         {
3482                 TableInfo  *tbinfo = &tblinfo[i];
3483
3484                 /* Ignore row security on tables not to be dumped */
3485                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3486                         continue;
3487
3488                 if (g_verbose)
3489                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3490                                           tbinfo->dobj.namespace->dobj.name,
3491                                           tbinfo->dobj.name);
3492
3493                 /*
3494                  * Get row security enabled information for the table. We represent
3495                  * RLS being enabled on a table by creating a PolicyInfo object with
3496                  * null polname.
3497                  */
3498                 if (tbinfo->rowsec)
3499                 {
3500                         /*
3501                          * Note: use tableoid 0 so that this object won't be mistaken for
3502                          * something that pg_depend entries apply to.
3503                          */
3504                         polinfo = pg_malloc(sizeof(PolicyInfo));
3505                         polinfo->dobj.objType = DO_POLICY;
3506                         polinfo->dobj.catId.tableoid = 0;
3507                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3508                         AssignDumpId(&polinfo->dobj);
3509                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3510                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3511                         polinfo->poltable = tbinfo;
3512                         polinfo->polname = NULL;
3513                         polinfo->polcmd = '\0';
3514                         polinfo->polpermissive = 0;
3515                         polinfo->polroles = NULL;
3516                         polinfo->polqual = NULL;
3517                         polinfo->polwithcheck = NULL;
3518                 }
3519
3520                 if (g_verbose)
3521                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3522                                           tbinfo->dobj.namespace->dobj.name,
3523                                           tbinfo->dobj.name);
3524
3525                 resetPQExpBuffer(query);
3526
3527                 /* Get the policies for the table. */
3528                 if (fout->remoteVersion >= 100000)
3529                         appendPQExpBuffer(query,
3530                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3531                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3532                                                           "   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, "
3533                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3534                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3535                                                           "FROM pg_catalog.pg_policy pol "
3536                                                           "WHERE polrelid = '%u'",
3537                                                           tbinfo->dobj.catId.oid);
3538                 else
3539                         appendPQExpBuffer(query,
3540                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3541                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3542                                                           "   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, "
3543                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3544                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3545                                                           "FROM pg_catalog.pg_policy pol "
3546                                                           "WHERE polrelid = '%u'",
3547                                                           tbinfo->dobj.catId.oid);
3548                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3549
3550                 ntups = PQntuples(res);
3551
3552                 if (ntups == 0)
3553                 {
3554                         /*
3555                          * No explicit policies to handle (only the default-deny policy,
3556                          * which is handled as part of the table definition).  Clean up
3557                          * and return.
3558                          */
3559                         PQclear(res);
3560                         continue;
3561                 }
3562
3563                 i_oid = PQfnumber(res, "oid");
3564                 i_tableoid = PQfnumber(res, "tableoid");
3565                 i_polname = PQfnumber(res, "polname");
3566                 i_polcmd = PQfnumber(res, "polcmd");
3567                 i_polpermissive = PQfnumber(res, "polpermissive");
3568                 i_polroles = PQfnumber(res, "polroles");
3569                 i_polqual = PQfnumber(res, "polqual");
3570                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3571
3572                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3573
3574                 for (j = 0; j < ntups; j++)
3575                 {
3576                         polinfo[j].dobj.objType = DO_POLICY;
3577                         polinfo[j].dobj.catId.tableoid =
3578                                 atooid(PQgetvalue(res, j, i_tableoid));
3579                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3580                         AssignDumpId(&polinfo[j].dobj);
3581                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3582                         polinfo[j].poltable = tbinfo;
3583                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3584                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3585
3586                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3587                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3588
3589                         if (PQgetisnull(res, j, i_polroles))
3590                                 polinfo[j].polroles = NULL;
3591                         else
3592                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3593
3594                         if (PQgetisnull(res, j, i_polqual))
3595                                 polinfo[j].polqual = NULL;
3596                         else
3597                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3598
3599                         if (PQgetisnull(res, j, i_polwithcheck))
3600                                 polinfo[j].polwithcheck = NULL;
3601                         else
3602                                 polinfo[j].polwithcheck
3603                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3604                 }
3605                 PQclear(res);
3606         }
3607         destroyPQExpBuffer(query);
3608 }
3609
3610 /*
3611  * dumpPolicy
3612  *        dump the definition of the given policy
3613  */
3614 static void
3615 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3616 {
3617         DumpOptions *dopt = fout->dopt;
3618         TableInfo  *tbinfo = polinfo->poltable;
3619         PQExpBuffer query;
3620         PQExpBuffer delqry;
3621         const char *cmd;
3622         char       *tag;
3623
3624         if (dopt->dataOnly)
3625                 return;
3626
3627         /*
3628          * If polname is NULL, then this record is just indicating that ROW LEVEL
3629          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3630          * ROW LEVEL SECURITY.
3631          */
3632         if (polinfo->polname == NULL)
3633         {
3634                 query = createPQExpBuffer();
3635
3636                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3637                                                   fmtQualifiedDumpable(tbinfo));
3638
3639                 /*
3640                  * We must emit the ROW SECURITY object's dependency on its table
3641                  * explicitly, because it will not match anything in pg_depend (unlike
3642                  * the case for other PolicyInfo objects).
3643                  */
3644                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3645                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3646                                                  polinfo->dobj.name,
3647                                                  polinfo->dobj.namespace->dobj.name,
3648                                                  NULL,
3649                                                  tbinfo->rolname, false,
3650                                                  "ROW SECURITY", SECTION_POST_DATA,
3651                                                  query->data, "", NULL,
3652                                                  &(tbinfo->dobj.dumpId), 1,
3653                                                  NULL, NULL);
3654
3655                 destroyPQExpBuffer(query);
3656                 return;
3657         }
3658
3659         if (polinfo->polcmd == '*')
3660                 cmd = "";
3661         else if (polinfo->polcmd == 'r')
3662                 cmd = " FOR SELECT";
3663         else if (polinfo->polcmd == 'a')
3664                 cmd = " FOR INSERT";
3665         else if (polinfo->polcmd == 'w')
3666                 cmd = " FOR UPDATE";
3667         else if (polinfo->polcmd == 'd')
3668                 cmd = " FOR DELETE";
3669         else
3670         {
3671                 write_msg(NULL, "unexpected policy command type: %c\n",
3672                                   polinfo->polcmd);
3673                 exit_nicely(1);
3674         }
3675
3676         query = createPQExpBuffer();
3677         delqry = createPQExpBuffer();
3678
3679         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3680
3681         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3682                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3683
3684         if (polinfo->polroles != NULL)
3685                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3686
3687         if (polinfo->polqual != NULL)
3688                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3689
3690         if (polinfo->polwithcheck != NULL)
3691                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3692
3693         appendPQExpBuffer(query, ";\n");
3694
3695         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3696         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3697
3698         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3699
3700         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3701                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3702                                          tag,
3703                                          polinfo->dobj.namespace->dobj.name,
3704                                          NULL,
3705                                          tbinfo->rolname, false,
3706                                          "POLICY", SECTION_POST_DATA,
3707                                          query->data, delqry->data, NULL,
3708                                          NULL, 0,
3709                                          NULL, NULL);
3710
3711         free(tag);
3712         destroyPQExpBuffer(query);
3713         destroyPQExpBuffer(delqry);
3714 }
3715
3716 /*
3717  * getPublications
3718  *        get information about publications
3719  */
3720 void
3721 getPublications(Archive *fout)
3722 {
3723         DumpOptions *dopt = fout->dopt;
3724         PQExpBuffer query;
3725         PGresult   *res;
3726         PublicationInfo *pubinfo;
3727         int                     i_tableoid;
3728         int                     i_oid;
3729         int                     i_pubname;
3730         int                     i_rolname;
3731         int                     i_puballtables;
3732         int                     i_pubinsert;
3733         int                     i_pubupdate;
3734         int                     i_pubdelete;
3735         int                     i_pubtruncate;
3736         int                     i,
3737                                 ntups;
3738
3739         if (dopt->no_publications || fout->remoteVersion < 100000)
3740                 return;
3741
3742         query = createPQExpBuffer();
3743
3744         resetPQExpBuffer(query);
3745
3746         /* Get the publications. */
3747         if (fout->remoteVersion >= 110000)
3748                 appendPQExpBuffer(query,
3749                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3750                                                   "(%s p.pubowner) AS rolname, "
3751                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3752                                                   "FROM pg_publication p",
3753                                                   username_subquery);
3754         else
3755                 appendPQExpBuffer(query,
3756                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3757                                                   "(%s p.pubowner) AS rolname, "
3758                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3759                                                   "FROM pg_publication p",
3760                                                   username_subquery);
3761
3762         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3763
3764         ntups = PQntuples(res);
3765
3766         i_tableoid = PQfnumber(res, "tableoid");
3767         i_oid = PQfnumber(res, "oid");
3768         i_pubname = PQfnumber(res, "pubname");
3769         i_rolname = PQfnumber(res, "rolname");
3770         i_puballtables = PQfnumber(res, "puballtables");
3771         i_pubinsert = PQfnumber(res, "pubinsert");
3772         i_pubupdate = PQfnumber(res, "pubupdate");
3773         i_pubdelete = PQfnumber(res, "pubdelete");
3774         i_pubtruncate = PQfnumber(res, "pubtruncate");
3775
3776         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3777
3778         for (i = 0; i < ntups; i++)
3779         {
3780                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3781                 pubinfo[i].dobj.catId.tableoid =
3782                         atooid(PQgetvalue(res, i, i_tableoid));
3783                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3784                 AssignDumpId(&pubinfo[i].dobj);
3785                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3786                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3787                 pubinfo[i].puballtables =
3788                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3789                 pubinfo[i].pubinsert =
3790                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3791                 pubinfo[i].pubupdate =
3792                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3793                 pubinfo[i].pubdelete =
3794                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3795                 pubinfo[i].pubtruncate =
3796                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3797
3798                 if (strlen(pubinfo[i].rolname) == 0)
3799                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3800                                           pubinfo[i].dobj.name);
3801
3802                 /* Decide whether we want to dump it */
3803                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3804         }
3805         PQclear(res);
3806
3807         destroyPQExpBuffer(query);
3808 }
3809
3810 /*
3811  * dumpPublication
3812  *        dump the definition of the given publication
3813  */
3814 static void
3815 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3816 {
3817         PQExpBuffer delq;
3818         PQExpBuffer query;
3819         char       *qpubname;
3820         bool            first = true;
3821
3822         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3823                 return;
3824
3825         delq = createPQExpBuffer();
3826         query = createPQExpBuffer();
3827
3828         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3829
3830         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3831                                           qpubname);
3832
3833         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3834                                           qpubname);
3835
3836         if (pubinfo->puballtables)
3837                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3838
3839         appendPQExpBufferStr(query, " WITH (publish = '");
3840         if (pubinfo->pubinsert)
3841         {
3842                 appendPQExpBufferStr(query, "insert");
3843                 first = false;
3844         }
3845
3846         if (pubinfo->pubupdate)
3847         {
3848                 if (!first)
3849                         appendPQExpBufferStr(query, ", ");
3850
3851                 appendPQExpBufferStr(query, "update");
3852                 first = false;
3853         }
3854
3855         if (pubinfo->pubdelete)
3856         {
3857                 if (!first)
3858                         appendPQExpBufferStr(query, ", ");
3859
3860                 appendPQExpBufferStr(query, "delete");
3861                 first = false;
3862         }
3863
3864         if (pubinfo->pubtruncate)
3865         {
3866                 if (!first)
3867                         appendPQExpBufferStr(query, ", ");
3868
3869                 appendPQExpBufferStr(query, "truncate");
3870                 first = false;
3871         }
3872
3873         appendPQExpBufferStr(query, "');\n");
3874
3875         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3876                                  pubinfo->dobj.name,
3877                                  NULL,
3878                                  NULL,
3879                                  pubinfo->rolname, false,
3880                                  "PUBLICATION", SECTION_POST_DATA,
3881                                  query->data, delq->data, NULL,
3882                                  NULL, 0,
3883                                  NULL, NULL);
3884
3885         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3886                 dumpComment(fout, "PUBLICATION", qpubname,
3887                                         NULL, pubinfo->rolname,
3888                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3889
3890         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3891                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3892                                          NULL, pubinfo->rolname,
3893                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3894
3895         destroyPQExpBuffer(delq);
3896         destroyPQExpBuffer(query);
3897         free(qpubname);
3898 }
3899
3900 /*
3901  * getPublicationTables
3902  *        get information about publication membership for dumpable tables.
3903  */
3904 void
3905 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3906 {
3907         PQExpBuffer query;
3908         PGresult   *res;
3909         PublicationRelInfo *pubrinfo;
3910         int                     i_tableoid;
3911         int                     i_oid;
3912         int                     i_pubname;
3913         int                     i,
3914                                 j,
3915                                 ntups;
3916
3917         if (fout->remoteVersion < 100000)
3918                 return;
3919
3920         query = createPQExpBuffer();
3921
3922         for (i = 0; i < numTables; i++)
3923         {
3924                 TableInfo  *tbinfo = &tblinfo[i];
3925
3926                 /* Only plain tables can be aded to publications. */
3927                 if (tbinfo->relkind != RELKIND_RELATION)
3928                         continue;
3929
3930                 /*
3931                  * Ignore publication membership of tables whose definitions are not
3932                  * to be dumped.
3933                  */
3934                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3935                         continue;
3936
3937                 if (g_verbose)
3938                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3939                                           tbinfo->dobj.namespace->dobj.name,
3940                                           tbinfo->dobj.name);
3941
3942                 resetPQExpBuffer(query);
3943
3944                 /* Get the publication membership for the table. */
3945                 appendPQExpBuffer(query,
3946                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3947                                                   "FROM pg_publication_rel pr, pg_publication p "
3948                                                   "WHERE pr.prrelid = '%u'"
3949                                                   "  AND p.oid = pr.prpubid",
3950                                                   tbinfo->dobj.catId.oid);
3951                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3952
3953                 ntups = PQntuples(res);
3954
3955                 if (ntups == 0)
3956                 {
3957                         /*
3958                          * Table is not member of any publications. Clean up and return.
3959                          */
3960                         PQclear(res);
3961                         continue;
3962                 }
3963
3964                 i_tableoid = PQfnumber(res, "tableoid");
3965                 i_oid = PQfnumber(res, "oid");
3966                 i_pubname = PQfnumber(res, "pubname");
3967
3968                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3969
3970                 for (j = 0; j < ntups; j++)
3971                 {
3972                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3973                         pubrinfo[j].dobj.catId.tableoid =
3974                                 atooid(PQgetvalue(res, j, i_tableoid));
3975                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3976                         AssignDumpId(&pubrinfo[j].dobj);
3977                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3978                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3979                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3980                         pubrinfo[j].pubtable = tbinfo;
3981
3982                         /* Decide whether we want to dump it */
3983                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
3984                 }
3985                 PQclear(res);
3986         }
3987         destroyPQExpBuffer(query);
3988 }
3989
3990 /*
3991  * dumpPublicationTable
3992  *        dump the definition of the given publication table mapping
3993  */
3994 static void
3995 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
3996 {
3997         TableInfo  *tbinfo = pubrinfo->pubtable;
3998         PQExpBuffer query;
3999         char       *tag;
4000
4001         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4002                 return;
4003
4004         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
4005
4006         query = createPQExpBuffer();
4007
4008         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4009                                           fmtId(pubrinfo->pubname));
4010         appendPQExpBuffer(query, " %s;\n",
4011                                           fmtQualifiedDumpable(tbinfo));
4012
4013         /*
4014          * There is no point in creating drop query as drop query as the drop is
4015          * done by table drop.
4016          */
4017         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4018                                  tag,
4019                                  tbinfo->dobj.namespace->dobj.name,
4020                                  NULL,
4021                                  "", false,
4022                                  "PUBLICATION TABLE", SECTION_POST_DATA,
4023                                  query->data, "", NULL,
4024                                  NULL, 0,
4025                                  NULL, NULL);
4026
4027         free(tag);
4028         destroyPQExpBuffer(query);
4029 }
4030
4031 /*
4032  * Is the currently connected user a superuser?
4033  */
4034 static bool
4035 is_superuser(Archive *fout)
4036 {
4037         ArchiveHandle *AH = (ArchiveHandle *) fout;
4038         const char *val;
4039
4040         val = PQparameterStatus(AH->connection, "is_superuser");
4041
4042         if (val && strcmp(val, "on") == 0)
4043                 return true;
4044
4045         return false;
4046 }
4047
4048 /*
4049  * getSubscriptions
4050  *        get information about subscriptions
4051  */
4052 void
4053 getSubscriptions(Archive *fout)
4054 {
4055         DumpOptions *dopt = fout->dopt;
4056         PQExpBuffer query;
4057         PGresult   *res;
4058         SubscriptionInfo *subinfo;
4059         int                     i_tableoid;
4060         int                     i_oid;
4061         int                     i_subname;
4062         int                     i_rolname;
4063         int                     i_subconninfo;
4064         int                     i_subslotname;
4065         int                     i_subsynccommit;
4066         int                     i_subpublications;
4067         int                     i,
4068                                 ntups;
4069
4070         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4071                 return;
4072
4073         if (!is_superuser(fout))
4074         {
4075                 int                     n;
4076
4077                 res = ExecuteSqlQuery(fout,
4078                                                           "SELECT count(*) FROM pg_subscription "
4079                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4080                                                           "                 WHERE datname = current_database())",
4081                                                           PGRES_TUPLES_OK);
4082                 n = atoi(PQgetvalue(res, 0, 0));
4083                 if (n > 0)
4084                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4085                 PQclear(res);
4086                 return;
4087         }
4088
4089         query = createPQExpBuffer();
4090
4091         resetPQExpBuffer(query);
4092
4093         /* Get the subscriptions in current database. */
4094         appendPQExpBuffer(query,
4095                                           "SELECT s.tableoid, s.oid, s.subname,"
4096                                           "(%s s.subowner) AS rolname, "
4097                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4098                                           " s.subpublications "
4099                                           "FROM pg_subscription s "
4100                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4101                                           "                   WHERE datname = current_database())",
4102                                           username_subquery);
4103         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4104
4105         ntups = PQntuples(res);
4106
4107         i_tableoid = PQfnumber(res, "tableoid");
4108         i_oid = PQfnumber(res, "oid");
4109         i_subname = PQfnumber(res, "subname");
4110         i_rolname = PQfnumber(res, "rolname");
4111         i_subconninfo = PQfnumber(res, "subconninfo");
4112         i_subslotname = PQfnumber(res, "subslotname");
4113         i_subsynccommit = PQfnumber(res, "subsynccommit");
4114         i_subpublications = PQfnumber(res, "subpublications");
4115
4116         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4117
4118         for (i = 0; i < ntups; i++)
4119         {
4120                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4121                 subinfo[i].dobj.catId.tableoid =
4122                         atooid(PQgetvalue(res, i, i_tableoid));
4123                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4124                 AssignDumpId(&subinfo[i].dobj);
4125                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4126                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4127                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4128                 if (PQgetisnull(res, i, i_subslotname))
4129                         subinfo[i].subslotname = NULL;
4130                 else
4131                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4132                 subinfo[i].subsynccommit =
4133                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4134                 subinfo[i].subpublications =
4135                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4136
4137                 if (strlen(subinfo[i].rolname) == 0)
4138                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4139                                           subinfo[i].dobj.name);
4140
4141                 /* Decide whether we want to dump it */
4142                 selectDumpableObject(&(subinfo[i].dobj), fout);
4143         }
4144         PQclear(res);
4145
4146         destroyPQExpBuffer(query);
4147 }
4148
4149 /*
4150  * dumpSubscription
4151  *        dump the definition of the given subscription
4152  */
4153 static void
4154 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4155 {
4156         PQExpBuffer delq;
4157         PQExpBuffer query;
4158         PQExpBuffer publications;
4159         char       *qsubname;
4160         char      **pubnames = NULL;
4161         int                     npubnames = 0;
4162         int                     i;
4163
4164         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4165                 return;
4166
4167         delq = createPQExpBuffer();
4168         query = createPQExpBuffer();
4169
4170         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4171
4172         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4173                                           qsubname);
4174
4175         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4176                                           qsubname);
4177         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4178
4179         /* Build list of quoted publications and append them to query. */
4180         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4181         {
4182                 write_msg(NULL,
4183                                   "WARNING: could not parse subpublications array\n");
4184                 if (pubnames)
4185                         free(pubnames);
4186                 pubnames = NULL;
4187                 npubnames = 0;
4188         }
4189
4190         publications = createPQExpBuffer();
4191         for (i = 0; i < npubnames; i++)
4192         {
4193                 if (i > 0)
4194                         appendPQExpBufferStr(publications, ", ");
4195
4196                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4197         }
4198
4199         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4200         if (subinfo->subslotname)
4201                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4202         else
4203                 appendPQExpBufferStr(query, "NONE");
4204
4205         if (strcmp(subinfo->subsynccommit, "off") != 0)
4206                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4207
4208         appendPQExpBufferStr(query, ");\n");
4209
4210         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4211                                  subinfo->dobj.name,
4212                                  NULL,
4213                                  NULL,
4214                                  subinfo->rolname, false,
4215                                  "SUBSCRIPTION", SECTION_POST_DATA,
4216                                  query->data, delq->data, NULL,
4217                                  NULL, 0,
4218                                  NULL, NULL);
4219
4220         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4221                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4222                                         NULL, subinfo->rolname,
4223                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4224
4225         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4226                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4227                                          NULL, subinfo->rolname,
4228                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4229
4230         destroyPQExpBuffer(publications);
4231         if (pubnames)
4232                 free(pubnames);
4233
4234         destroyPQExpBuffer(delq);
4235         destroyPQExpBuffer(query);
4236         free(qsubname);
4237 }
4238
4239 static void
4240 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4241                                                                                  PQExpBuffer upgrade_buffer,
4242                                                                                  Oid pg_type_oid,
4243                                                                                  bool force_array_type)
4244 {
4245         PQExpBuffer upgrade_query = createPQExpBuffer();
4246         PGresult   *res;
4247         Oid                     pg_type_array_oid;
4248
4249         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4250         appendPQExpBuffer(upgrade_buffer,
4251                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4252                                           pg_type_oid);
4253
4254         /* we only support old >= 8.3 for binary upgrades */
4255         appendPQExpBuffer(upgrade_query,
4256                                           "SELECT typarray "
4257                                           "FROM pg_catalog.pg_type "
4258                                           "WHERE oid = '%u'::pg_catalog.oid;",
4259                                           pg_type_oid);
4260
4261         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4262
4263         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4264
4265         PQclear(res);
4266
4267         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4268         {
4269                 /*
4270                  * If the old version didn't assign an array type, but the new version
4271                  * does, we must select an unused type OID to assign.  This currently
4272                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4273                  *
4274                  * Note: local state here is kind of ugly, but we must have some,
4275                  * since we mustn't choose the same unused OID more than once.
4276                  */
4277                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4278                 bool            is_dup;
4279
4280                 do
4281                 {
4282                         ++next_possible_free_oid;
4283                         printfPQExpBuffer(upgrade_query,
4284                                                           "SELECT EXISTS(SELECT 1 "
4285                                                           "FROM pg_catalog.pg_type "
4286                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4287                                                           next_possible_free_oid);
4288                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4289                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4290                         PQclear(res);
4291                 } while (is_dup);
4292
4293                 pg_type_array_oid = next_possible_free_oid;
4294         }
4295
4296         if (OidIsValid(pg_type_array_oid))
4297         {
4298                 appendPQExpBufferStr(upgrade_buffer,
4299                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4300                 appendPQExpBuffer(upgrade_buffer,
4301                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4302                                                   pg_type_array_oid);
4303         }
4304
4305         destroyPQExpBuffer(upgrade_query);
4306 }
4307
4308 static bool
4309 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4310                                                                                 PQExpBuffer upgrade_buffer,
4311                                                                                 Oid pg_rel_oid)
4312 {
4313         PQExpBuffer upgrade_query = createPQExpBuffer();
4314         PGresult   *upgrade_res;
4315         Oid                     pg_type_oid;
4316         bool            toast_set = false;
4317
4318         /* we only support old >= 8.3 for binary upgrades */
4319         appendPQExpBuffer(upgrade_query,
4320                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4321                                           "FROM pg_catalog.pg_class c "
4322                                           "LEFT JOIN pg_catalog.pg_class t ON "
4323                                           "  (c.reltoastrelid = t.oid) "
4324                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4325                                           pg_rel_oid);
4326
4327         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4328
4329         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4330
4331         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4332                                                                                          pg_type_oid, false);
4333
4334         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4335         {
4336                 /* Toast tables do not have pg_type array rows */
4337                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4338                                                                                                                   PQfnumber(upgrade_res, "trel")));
4339
4340                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4341                 appendPQExpBuffer(upgrade_buffer,
4342                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4343                                                   pg_type_toast_oid);
4344
4345                 toast_set = true;
4346         }
4347
4348         PQclear(upgrade_res);
4349         destroyPQExpBuffer(upgrade_query);
4350
4351         return toast_set;
4352 }
4353
4354 static void
4355 binary_upgrade_set_pg_class_oids(Archive *fout,
4356                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4357                                                                  bool is_index)
4358 {
4359         PQExpBuffer upgrade_query = createPQExpBuffer();
4360         PGresult   *upgrade_res;
4361         Oid                     pg_class_reltoastrelid;
4362         Oid                     pg_index_indexrelid;
4363
4364         appendPQExpBuffer(upgrade_query,
4365                                           "SELECT c.reltoastrelid, i.indexrelid "
4366                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4367                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4368                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4369                                           pg_class_oid);
4370
4371         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4372
4373         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4374         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4375
4376         appendPQExpBufferStr(upgrade_buffer,
4377                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4378
4379         if (!is_index)
4380         {
4381                 appendPQExpBuffer(upgrade_buffer,
4382                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4383                                                   pg_class_oid);
4384                 /* only tables have toast tables, not indexes */
4385                 if (OidIsValid(pg_class_reltoastrelid))
4386                 {
4387                         /*
4388                          * One complexity is that the table definition might not require
4389                          * the creation of a TOAST table, and the TOAST table might have
4390                          * been created long after table creation, when the table was
4391                          * loaded with wide data.  By setting the TOAST oid we force
4392                          * creation of the TOAST heap and TOAST index by the backend so we
4393                          * can cleanly copy the files during binary upgrade.
4394                          */
4395
4396                         appendPQExpBuffer(upgrade_buffer,
4397                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4398                                                           pg_class_reltoastrelid);
4399
4400                         /* every toast table has an index */
4401                         appendPQExpBuffer(upgrade_buffer,
4402                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4403                                                           pg_index_indexrelid);
4404                 }
4405         }
4406         else
4407                 appendPQExpBuffer(upgrade_buffer,
4408                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4409                                                   pg_class_oid);
4410
4411         appendPQExpBufferChar(upgrade_buffer, '\n');
4412
4413         PQclear(upgrade_res);
4414         destroyPQExpBuffer(upgrade_query);
4415 }
4416
4417 /*
4418  * If the DumpableObject is a member of an extension, add a suitable
4419  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4420  *
4421  * For somewhat historical reasons, objname should already be quoted,
4422  * but not objnamespace (if any).
4423  */
4424 static void
4425 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4426                                                                 DumpableObject *dobj,
4427                                                                 const char *objtype,
4428                                                                 const char *objname,
4429                                                                 const char *objnamespace)
4430 {
4431         DumpableObject *extobj = NULL;
4432         int                     i;
4433
4434         if (!dobj->ext_member)
4435                 return;
4436
4437         /*
4438          * Find the parent extension.  We could avoid this search if we wanted to
4439          * add a link field to DumpableObject, but the space costs of that would
4440          * be considerable.  We assume that member objects could only have a
4441          * direct dependency on their own extension, not any others.
4442          */
4443         for (i = 0; i < dobj->nDeps; i++)
4444         {
4445                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4446                 if (extobj && extobj->objType == DO_EXTENSION)
4447                         break;
4448                 extobj = NULL;
4449         }
4450         if (extobj == NULL)
4451                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4452                                           objtype, objname);
4453
4454         appendPQExpBufferStr(upgrade_buffer,
4455                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4456         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4457                                           fmtId(extobj->name),
4458                                           objtype);
4459         if (objnamespace && *objnamespace)
4460                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4461         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4462 }
4463
4464 /*
4465  * getNamespaces:
4466  *        read all namespaces in the system catalogs and return them in the
4467  * NamespaceInfo* structure
4468  *
4469  *      numNamespaces is set to the number of namespaces read in
4470  */
4471 NamespaceInfo *
4472 getNamespaces(Archive *fout, int *numNamespaces)
4473 {
4474         DumpOptions *dopt = fout->dopt;
4475         PGresult   *res;
4476         int                     ntups;
4477         int                     i;
4478         PQExpBuffer query;
4479         NamespaceInfo *nsinfo;
4480         int                     i_tableoid;
4481         int                     i_oid;
4482         int                     i_nspname;
4483         int                     i_rolname;
4484         int                     i_nspacl;
4485         int                     i_rnspacl;
4486         int                     i_initnspacl;
4487         int                     i_initrnspacl;
4488
4489         query = createPQExpBuffer();
4490
4491         /*
4492          * we fetch all namespaces including system ones, so that every object we
4493          * read in can be linked to a containing namespace.
4494          */
4495         if (fout->remoteVersion >= 90600)
4496         {
4497                 PQExpBuffer acl_subquery = createPQExpBuffer();
4498                 PQExpBuffer racl_subquery = createPQExpBuffer();
4499                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4500                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4501
4502                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4503                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4504                                                 dopt->binary_upgrade);
4505
4506                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4507                                                   "(%s nspowner) AS rolname, "
4508                                                   "%s as nspacl, "
4509                                                   "%s as rnspacl, "
4510                                                   "%s as initnspacl, "
4511                                                   "%s as initrnspacl "
4512                                                   "FROM pg_namespace n "
4513                                                   "LEFT JOIN pg_init_privs pip "
4514                                                   "ON (n.oid = pip.objoid "
4515                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4516                                                   "AND pip.objsubid = 0",
4517                                                   username_subquery,
4518                                                   acl_subquery->data,
4519                                                   racl_subquery->data,
4520                                                   init_acl_subquery->data,
4521                                                   init_racl_subquery->data);
4522
4523                 appendPQExpBuffer(query, ") ");
4524
4525                 destroyPQExpBuffer(acl_subquery);
4526                 destroyPQExpBuffer(racl_subquery);
4527                 destroyPQExpBuffer(init_acl_subquery);
4528                 destroyPQExpBuffer(init_racl_subquery);
4529         }
4530         else
4531                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4532                                                   "(%s nspowner) AS rolname, "
4533                                                   "nspacl, NULL as rnspacl, "
4534                                                   "NULL AS initnspacl, NULL as initrnspacl "
4535                                                   "FROM pg_namespace",
4536                                                   username_subquery);
4537
4538         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4539
4540         ntups = PQntuples(res);
4541
4542         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4543
4544         i_tableoid = PQfnumber(res, "tableoid");
4545         i_oid = PQfnumber(res, "oid");
4546         i_nspname = PQfnumber(res, "nspname");
4547         i_rolname = PQfnumber(res, "rolname");
4548         i_nspacl = PQfnumber(res, "nspacl");
4549         i_rnspacl = PQfnumber(res, "rnspacl");
4550         i_initnspacl = PQfnumber(res, "initnspacl");
4551         i_initrnspacl = PQfnumber(res, "initrnspacl");
4552
4553         for (i = 0; i < ntups; i++)
4554         {
4555                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4556                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4557                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4558                 AssignDumpId(&nsinfo[i].dobj);
4559                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4560                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4561                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4562                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4563                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4564                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4565
4566                 /* Decide whether to dump this namespace */
4567                 selectDumpableNamespace(&nsinfo[i], fout);
4568
4569                 /*
4570                  * Do not try to dump ACL if the ACL is empty or the default.
4571                  *
4572                  * This is useful because, for some schemas/objects, the only
4573                  * component we are going to try and dump is the ACL and if we can
4574                  * remove that then 'dump' goes to zero/false and we don't consider
4575                  * this object for dumping at all later on.
4576                  */
4577                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4578                         PQgetisnull(res, i, i_initnspacl) &&
4579                         PQgetisnull(res, i, i_initrnspacl))
4580                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4581
4582                 if (strlen(nsinfo[i].rolname) == 0)
4583                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4584                                           nsinfo[i].dobj.name);
4585         }
4586
4587         PQclear(res);
4588         destroyPQExpBuffer(query);
4589
4590         *numNamespaces = ntups;
4591
4592         return nsinfo;
4593 }
4594
4595 /*
4596  * findNamespace:
4597  *              given a namespace OID, look up the info read by getNamespaces
4598  */
4599 static NamespaceInfo *
4600 findNamespace(Archive *fout, Oid nsoid)
4601 {
4602         NamespaceInfo *nsinfo;
4603
4604         nsinfo = findNamespaceByOid(nsoid);
4605         if (nsinfo == NULL)
4606                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4607         return nsinfo;
4608 }
4609
4610 /*
4611  * getExtensions:
4612  *        read all extensions in the system catalogs and return them in the
4613  * ExtensionInfo* structure
4614  *
4615  *      numExtensions is set to the number of extensions read in
4616  */
4617 ExtensionInfo *
4618 getExtensions(Archive *fout, int *numExtensions)
4619 {
4620         DumpOptions *dopt = fout->dopt;
4621         PGresult   *res;
4622         int                     ntups;
4623         int                     i;
4624         PQExpBuffer query;
4625         ExtensionInfo *extinfo;
4626         int                     i_tableoid;
4627         int                     i_oid;
4628         int                     i_extname;
4629         int                     i_nspname;
4630         int                     i_extrelocatable;
4631         int                     i_extversion;
4632         int                     i_extconfig;
4633         int                     i_extcondition;
4634
4635         /*
4636          * Before 9.1, there are no extensions.
4637          */
4638         if (fout->remoteVersion < 90100)
4639         {
4640                 *numExtensions = 0;
4641                 return NULL;
4642         }
4643
4644         query = createPQExpBuffer();
4645
4646         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4647                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4648                                                  "FROM pg_extension x "
4649                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4650
4651         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4652
4653         ntups = PQntuples(res);
4654
4655         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4656
4657         i_tableoid = PQfnumber(res, "tableoid");
4658         i_oid = PQfnumber(res, "oid");
4659         i_extname = PQfnumber(res, "extname");
4660         i_nspname = PQfnumber(res, "nspname");
4661         i_extrelocatable = PQfnumber(res, "extrelocatable");
4662         i_extversion = PQfnumber(res, "extversion");
4663         i_extconfig = PQfnumber(res, "extconfig");
4664         i_extcondition = PQfnumber(res, "extcondition");
4665
4666         for (i = 0; i < ntups; i++)
4667         {
4668                 extinfo[i].dobj.objType = DO_EXTENSION;
4669                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4670                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4671                 AssignDumpId(&extinfo[i].dobj);
4672                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4673                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4674                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4675                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4676                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4677                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4678
4679                 /* Decide whether we want to dump it */
4680                 selectDumpableExtension(&(extinfo[i]), dopt);
4681         }
4682
4683         PQclear(res);
4684         destroyPQExpBuffer(query);
4685
4686         *numExtensions = ntups;
4687
4688         return extinfo;
4689 }
4690
4691 /*
4692  * getTypes:
4693  *        read all types in the system catalogs and return them in the
4694  * TypeInfo* structure
4695  *
4696  *      numTypes is set to the number of types read in
4697  *
4698  * NB: this must run after getFuncs() because we assume we can do
4699  * findFuncByOid().
4700  */
4701 TypeInfo *
4702 getTypes(Archive *fout, int *numTypes)
4703 {
4704         DumpOptions *dopt = fout->dopt;
4705         PGresult   *res;
4706         int                     ntups;
4707         int                     i;
4708         PQExpBuffer query = createPQExpBuffer();
4709         TypeInfo   *tyinfo;
4710         ShellTypeInfo *stinfo;
4711         int                     i_tableoid;
4712         int                     i_oid;
4713         int                     i_typname;
4714         int                     i_typnamespace;
4715         int                     i_typacl;
4716         int                     i_rtypacl;
4717         int                     i_inittypacl;
4718         int                     i_initrtypacl;
4719         int                     i_rolname;
4720         int                     i_typelem;
4721         int                     i_typrelid;
4722         int                     i_typrelkind;
4723         int                     i_typtype;
4724         int                     i_typisdefined;
4725         int                     i_isarray;
4726
4727         /*
4728          * we include even the built-in types because those may be used as array
4729          * elements by user-defined types
4730          *
4731          * we filter out the built-in types when we dump out the types
4732          *
4733          * same approach for undefined (shell) types and array types
4734          *
4735          * Note: as of 8.3 we can reliably detect whether a type is an
4736          * auto-generated array type by checking the element type's typarray.
4737          * (Before that the test is capable of generating false positives.) We
4738          * still check for name beginning with '_', though, so as to avoid the
4739          * cost of the subselect probe for all standard types.  This would have to
4740          * be revisited if the backend ever allows renaming of array types.
4741          */
4742
4743         if (fout->remoteVersion >= 90600)
4744         {
4745                 PQExpBuffer acl_subquery = createPQExpBuffer();
4746                 PQExpBuffer racl_subquery = createPQExpBuffer();
4747                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4748                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4749
4750                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4751                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4752                                                 dopt->binary_upgrade);
4753
4754                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4755                                                   "t.typnamespace, "
4756                                                   "%s AS typacl, "
4757                                                   "%s AS rtypacl, "
4758                                                   "%s AS inittypacl, "
4759                                                   "%s AS initrtypacl, "
4760                                                   "(%s t.typowner) AS rolname, "
4761                                                   "t.typelem, t.typrelid, "
4762                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4763                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4764                                                   "t.typtype, t.typisdefined, "
4765                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4766                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4767                                                   "FROM pg_type t "
4768                                                   "LEFT JOIN pg_init_privs pip ON "
4769                                                   "(t.oid = pip.objoid "
4770                                                   "AND pip.classoid = 'pg_type'::regclass "
4771                                                   "AND pip.objsubid = 0) ",
4772                                                   acl_subquery->data,
4773                                                   racl_subquery->data,
4774                                                   initacl_subquery->data,
4775                                                   initracl_subquery->data,
4776                                                   username_subquery);
4777
4778                 destroyPQExpBuffer(acl_subquery);
4779                 destroyPQExpBuffer(racl_subquery);
4780                 destroyPQExpBuffer(initacl_subquery);
4781                 destroyPQExpBuffer(initracl_subquery);
4782         }
4783         else if (fout->remoteVersion >= 90200)
4784         {
4785                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4786                                                   "typnamespace, typacl, NULL as rtypacl, "
4787                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4788                                                   "(%s typowner) AS rolname, "
4789                                                   "typelem, typrelid, "
4790                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4791                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4792                                                   "typtype, typisdefined, "
4793                                                   "typname[0] = '_' AND typelem != 0 AND "
4794                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4795                                                   "FROM pg_type",
4796                                                   username_subquery);
4797         }
4798         else if (fout->remoteVersion >= 80300)
4799         {
4800                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4801                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4802                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4803                                                   "(%s typowner) AS rolname, "
4804                                                   "typelem, typrelid, "
4805                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4806                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4807                                                   "typtype, typisdefined, "
4808                                                   "typname[0] = '_' AND typelem != 0 AND "
4809                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4810                                                   "FROM pg_type",
4811                                                   username_subquery);
4812         }
4813         else
4814         {
4815                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4816                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4817                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4818                                                   "(%s typowner) AS rolname, "
4819                                                   "typelem, typrelid, "
4820                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4821                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4822                                                   "typtype, typisdefined, "
4823                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4824                                                   "FROM pg_type",
4825                                                   username_subquery);
4826         }
4827
4828         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4829
4830         ntups = PQntuples(res);
4831
4832         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4833
4834         i_tableoid = PQfnumber(res, "tableoid");
4835         i_oid = PQfnumber(res, "oid");
4836         i_typname = PQfnumber(res, "typname");
4837         i_typnamespace = PQfnumber(res, "typnamespace");
4838         i_typacl = PQfnumber(res, "typacl");
4839         i_rtypacl = PQfnumber(res, "rtypacl");
4840         i_inittypacl = PQfnumber(res, "inittypacl");
4841         i_initrtypacl = PQfnumber(res, "initrtypacl");
4842         i_rolname = PQfnumber(res, "rolname");
4843         i_typelem = PQfnumber(res, "typelem");
4844         i_typrelid = PQfnumber(res, "typrelid");
4845         i_typrelkind = PQfnumber(res, "typrelkind");
4846         i_typtype = PQfnumber(res, "typtype");
4847         i_typisdefined = PQfnumber(res, "typisdefined");
4848         i_isarray = PQfnumber(res, "isarray");
4849
4850         for (i = 0; i < ntups; i++)
4851         {
4852                 tyinfo[i].dobj.objType = DO_TYPE;
4853                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4854                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4855                 AssignDumpId(&tyinfo[i].dobj);
4856                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4857                 tyinfo[i].dobj.namespace =
4858                         findNamespace(fout,
4859                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4860                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4861                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4862                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4863                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4864                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4865                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4866                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4867                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4868                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4869                 tyinfo[i].shellType = NULL;
4870
4871                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4872                         tyinfo[i].isDefined = true;
4873                 else
4874                         tyinfo[i].isDefined = false;
4875
4876                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4877                         tyinfo[i].isArray = true;
4878                 else
4879                         tyinfo[i].isArray = false;
4880
4881                 /* Decide whether we want to dump it */
4882                 selectDumpableType(&tyinfo[i], fout);
4883
4884                 /* Do not try to dump ACL if no ACL exists. */
4885                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4886                         PQgetisnull(res, i, i_inittypacl) &&
4887                         PQgetisnull(res, i, i_initrtypacl))
4888                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4889
4890                 /*
4891                  * If it's a domain, fetch info about its constraints, if any
4892                  */
4893                 tyinfo[i].nDomChecks = 0;
4894                 tyinfo[i].domChecks = NULL;
4895                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4896                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4897                         getDomainConstraints(fout, &(tyinfo[i]));
4898
4899                 /*
4900                  * If it's a base type, make a DumpableObject representing a shell
4901                  * definition of the type.  We will need to dump that ahead of the I/O
4902                  * functions for the type.  Similarly, range types need a shell
4903                  * definition in case they have a canonicalize function.
4904                  *
4905                  * Note: the shell type doesn't have a catId.  You might think it
4906                  * should copy the base type's catId, but then it might capture the
4907                  * pg_depend entries for the type, which we don't want.
4908                  */
4909                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4910                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4911                          tyinfo[i].typtype == TYPTYPE_RANGE))
4912                 {
4913                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4914                         stinfo->dobj.objType = DO_SHELL_TYPE;
4915                         stinfo->dobj.catId = nilCatalogId;
4916                         AssignDumpId(&stinfo->dobj);
4917                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4918                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4919                         stinfo->baseType = &(tyinfo[i]);
4920                         tyinfo[i].shellType = stinfo;
4921
4922                         /*
4923                          * Initially mark the shell type as not to be dumped.  We'll only
4924                          * dump it if the I/O or canonicalize functions need to be dumped;
4925                          * this is taken care of while sorting dependencies.
4926                          */
4927                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4928                 }
4929
4930                 if (strlen(tyinfo[i].rolname) == 0)
4931                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4932                                           tyinfo[i].dobj.name);
4933         }
4934
4935         *numTypes = ntups;
4936
4937         PQclear(res);
4938
4939         destroyPQExpBuffer(query);
4940
4941         return tyinfo;
4942 }
4943
4944 /*
4945  * getOperators:
4946  *        read all operators in the system catalogs and return them in the
4947  * OprInfo* structure
4948  *
4949  *      numOprs is set to the number of operators read in
4950  */
4951 OprInfo *
4952 getOperators(Archive *fout, int *numOprs)
4953 {
4954         PGresult   *res;
4955         int                     ntups;
4956         int                     i;
4957         PQExpBuffer query = createPQExpBuffer();
4958         OprInfo    *oprinfo;
4959         int                     i_tableoid;
4960         int                     i_oid;
4961         int                     i_oprname;
4962         int                     i_oprnamespace;
4963         int                     i_rolname;
4964         int                     i_oprkind;
4965         int                     i_oprcode;
4966
4967         /*
4968          * find all operators, including builtin operators; we filter out
4969          * system-defined operators at dump-out time.
4970          */
4971
4972         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4973                                           "oprnamespace, "
4974                                           "(%s oprowner) AS rolname, "
4975                                           "oprkind, "
4976                                           "oprcode::oid AS oprcode "
4977                                           "FROM pg_operator",
4978                                           username_subquery);
4979
4980         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4981
4982         ntups = PQntuples(res);
4983         *numOprs = ntups;
4984
4985         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4986
4987         i_tableoid = PQfnumber(res, "tableoid");
4988         i_oid = PQfnumber(res, "oid");
4989         i_oprname = PQfnumber(res, "oprname");
4990         i_oprnamespace = PQfnumber(res, "oprnamespace");
4991         i_rolname = PQfnumber(res, "rolname");
4992         i_oprkind = PQfnumber(res, "oprkind");
4993         i_oprcode = PQfnumber(res, "oprcode");
4994
4995         for (i = 0; i < ntups; i++)
4996         {
4997                 oprinfo[i].dobj.objType = DO_OPERATOR;
4998                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4999                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5000                 AssignDumpId(&oprinfo[i].dobj);
5001                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5002                 oprinfo[i].dobj.namespace =
5003                         findNamespace(fout,
5004                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
5005                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5006                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5007                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5008
5009                 /* Decide whether we want to dump it */
5010                 selectDumpableObject(&(oprinfo[i].dobj), fout);
5011
5012                 /* Operators do not currently have ACLs. */
5013                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5014
5015                 if (strlen(oprinfo[i].rolname) == 0)
5016                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
5017                                           oprinfo[i].dobj.name);
5018         }
5019
5020         PQclear(res);
5021
5022         destroyPQExpBuffer(query);
5023
5024         return oprinfo;
5025 }
5026
5027 /*
5028  * getCollations:
5029  *        read all collations in the system catalogs and return them in the
5030  * CollInfo* structure
5031  *
5032  *      numCollations is set to the number of collations read in
5033  */
5034 CollInfo *
5035 getCollations(Archive *fout, int *numCollations)
5036 {
5037         PGresult   *res;
5038         int                     ntups;
5039         int                     i;
5040         PQExpBuffer query;
5041         CollInfo   *collinfo;
5042         int                     i_tableoid;
5043         int                     i_oid;
5044         int                     i_collname;
5045         int                     i_collnamespace;
5046         int                     i_rolname;
5047
5048         /* Collations didn't exist pre-9.1 */
5049         if (fout->remoteVersion < 90100)
5050         {
5051                 *numCollations = 0;
5052                 return NULL;
5053         }
5054
5055         query = createPQExpBuffer();
5056
5057         /*
5058          * find all collations, including builtin collations; we filter out
5059          * system-defined collations at dump-out time.
5060          */
5061
5062         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5063                                           "collnamespace, "
5064                                           "(%s collowner) AS rolname "
5065                                           "FROM pg_collation",
5066                                           username_subquery);
5067
5068         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5069
5070         ntups = PQntuples(res);
5071         *numCollations = ntups;
5072
5073         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5074
5075         i_tableoid = PQfnumber(res, "tableoid");
5076         i_oid = PQfnumber(res, "oid");
5077         i_collname = PQfnumber(res, "collname");
5078         i_collnamespace = PQfnumber(res, "collnamespace");
5079         i_rolname = PQfnumber(res, "rolname");
5080
5081         for (i = 0; i < ntups; i++)
5082         {
5083                 collinfo[i].dobj.objType = DO_COLLATION;
5084                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5085                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5086                 AssignDumpId(&collinfo[i].dobj);
5087                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5088                 collinfo[i].dobj.namespace =
5089                         findNamespace(fout,
5090                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5091                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5092
5093                 /* Decide whether we want to dump it */
5094                 selectDumpableObject(&(collinfo[i].dobj), fout);
5095
5096                 /* Collations do not currently have ACLs. */
5097                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5098         }
5099
5100         PQclear(res);
5101
5102         destroyPQExpBuffer(query);
5103
5104         return collinfo;
5105 }
5106
5107 /*
5108  * getConversions:
5109  *        read all conversions in the system catalogs and return them in the
5110  * ConvInfo* structure
5111  *
5112  *      numConversions is set to the number of conversions read in
5113  */
5114 ConvInfo *
5115 getConversions(Archive *fout, int *numConversions)
5116 {
5117         PGresult   *res;
5118         int                     ntups;
5119         int                     i;
5120         PQExpBuffer query;
5121         ConvInfo   *convinfo;
5122         int                     i_tableoid;
5123         int                     i_oid;
5124         int                     i_conname;
5125         int                     i_connamespace;
5126         int                     i_rolname;
5127
5128         query = createPQExpBuffer();
5129
5130         /*
5131          * find all conversions, including builtin conversions; we filter out
5132          * system-defined conversions at dump-out time.
5133          */
5134
5135         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5136                                           "connamespace, "
5137                                           "(%s conowner) AS rolname "
5138                                           "FROM pg_conversion",
5139                                           username_subquery);
5140
5141         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5142
5143         ntups = PQntuples(res);
5144         *numConversions = ntups;
5145
5146         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5147
5148         i_tableoid = PQfnumber(res, "tableoid");
5149         i_oid = PQfnumber(res, "oid");
5150         i_conname = PQfnumber(res, "conname");
5151         i_connamespace = PQfnumber(res, "connamespace");
5152         i_rolname = PQfnumber(res, "rolname");
5153
5154         for (i = 0; i < ntups; i++)
5155         {
5156                 convinfo[i].dobj.objType = DO_CONVERSION;
5157                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5158                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5159                 AssignDumpId(&convinfo[i].dobj);
5160                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5161                 convinfo[i].dobj.namespace =
5162                         findNamespace(fout,
5163                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5164                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5165
5166                 /* Decide whether we want to dump it */
5167                 selectDumpableObject(&(convinfo[i].dobj), fout);
5168
5169                 /* Conversions do not currently have ACLs. */
5170                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5171         }
5172
5173         PQclear(res);
5174
5175         destroyPQExpBuffer(query);
5176
5177         return convinfo;
5178 }
5179
5180 /*
5181  * getAccessMethods:
5182  *        read all user-defined access methods in the system catalogs and return
5183  *        them in the AccessMethodInfo* structure
5184  *
5185  *      numAccessMethods is set to the number of access methods read in
5186  */
5187 AccessMethodInfo *
5188 getAccessMethods(Archive *fout, int *numAccessMethods)
5189 {
5190         PGresult   *res;
5191         int                     ntups;
5192         int                     i;
5193         PQExpBuffer query;
5194         AccessMethodInfo *aminfo;
5195         int                     i_tableoid;
5196         int                     i_oid;
5197         int                     i_amname;
5198         int                     i_amhandler;
5199         int                     i_amtype;
5200
5201         /* Before 9.6, there are no user-defined access methods */
5202         if (fout->remoteVersion < 90600)
5203         {
5204                 *numAccessMethods = 0;
5205                 return NULL;
5206         }
5207
5208         query = createPQExpBuffer();
5209
5210         /* Select all access methods from pg_am table */
5211         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5212                                           "amhandler::pg_catalog.regproc AS amhandler "
5213                                           "FROM pg_am");
5214
5215         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5216
5217         ntups = PQntuples(res);
5218         *numAccessMethods = ntups;
5219
5220         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5221
5222         i_tableoid = PQfnumber(res, "tableoid");
5223         i_oid = PQfnumber(res, "oid");
5224         i_amname = PQfnumber(res, "amname");
5225         i_amhandler = PQfnumber(res, "amhandler");
5226         i_amtype = PQfnumber(res, "amtype");
5227
5228         for (i = 0; i < ntups; i++)
5229         {
5230                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5231                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5232                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5233                 AssignDumpId(&aminfo[i].dobj);
5234                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5235                 aminfo[i].dobj.namespace = NULL;
5236                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5237                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5238
5239                 /* Decide whether we want to dump it */
5240                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5241
5242                 /* Access methods do not currently have ACLs. */
5243                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5244         }
5245
5246         PQclear(res);
5247
5248         destroyPQExpBuffer(query);
5249
5250         return aminfo;
5251 }
5252
5253
5254 /*
5255  * getOpclasses:
5256  *        read all opclasses in the system catalogs and return them in the
5257  * OpclassInfo* structure
5258  *
5259  *      numOpclasses is set to the number of opclasses read in
5260  */
5261 OpclassInfo *
5262 getOpclasses(Archive *fout, int *numOpclasses)
5263 {
5264         PGresult   *res;
5265         int                     ntups;
5266         int                     i;
5267         PQExpBuffer query = createPQExpBuffer();
5268         OpclassInfo *opcinfo;
5269         int                     i_tableoid;
5270         int                     i_oid;
5271         int                     i_opcname;
5272         int                     i_opcnamespace;
5273         int                     i_rolname;
5274
5275         /*
5276          * find all opclasses, including builtin opclasses; we filter out
5277          * system-defined opclasses at dump-out time.
5278          */
5279
5280         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5281                                           "opcnamespace, "
5282                                           "(%s opcowner) AS rolname "
5283                                           "FROM pg_opclass",
5284                                           username_subquery);
5285
5286         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5287
5288         ntups = PQntuples(res);
5289         *numOpclasses = ntups;
5290
5291         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5292
5293         i_tableoid = PQfnumber(res, "tableoid");
5294         i_oid = PQfnumber(res, "oid");
5295         i_opcname = PQfnumber(res, "opcname");
5296         i_opcnamespace = PQfnumber(res, "opcnamespace");
5297         i_rolname = PQfnumber(res, "rolname");
5298
5299         for (i = 0; i < ntups; i++)
5300         {
5301                 opcinfo[i].dobj.objType = DO_OPCLASS;
5302                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5303                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5304                 AssignDumpId(&opcinfo[i].dobj);
5305                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5306                 opcinfo[i].dobj.namespace =
5307                         findNamespace(fout,
5308                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5309                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5310
5311                 /* Decide whether we want to dump it */
5312                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5313
5314                 /* Op Classes do not currently have ACLs. */
5315                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5316
5317                 if (strlen(opcinfo[i].rolname) == 0)
5318                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5319                                           opcinfo[i].dobj.name);
5320         }
5321
5322         PQclear(res);
5323
5324         destroyPQExpBuffer(query);
5325
5326         return opcinfo;
5327 }
5328
5329 /*
5330  * getOpfamilies:
5331  *        read all opfamilies in the system catalogs and return them in the
5332  * OpfamilyInfo* structure
5333  *
5334  *      numOpfamilies is set to the number of opfamilies read in
5335  */
5336 OpfamilyInfo *
5337 getOpfamilies(Archive *fout, int *numOpfamilies)
5338 {
5339         PGresult   *res;
5340         int                     ntups;
5341         int                     i;
5342         PQExpBuffer query;
5343         OpfamilyInfo *opfinfo;
5344         int                     i_tableoid;
5345         int                     i_oid;
5346         int                     i_opfname;
5347         int                     i_opfnamespace;
5348         int                     i_rolname;
5349
5350         /* Before 8.3, there is no separate concept of opfamilies */
5351         if (fout->remoteVersion < 80300)
5352         {
5353                 *numOpfamilies = 0;
5354                 return NULL;
5355         }
5356
5357         query = createPQExpBuffer();
5358
5359         /*
5360          * find all opfamilies, including builtin opfamilies; we filter out
5361          * system-defined opfamilies at dump-out time.
5362          */
5363
5364         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5365                                           "opfnamespace, "
5366                                           "(%s opfowner) AS rolname "
5367                                           "FROM pg_opfamily",
5368                                           username_subquery);
5369
5370         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5371
5372         ntups = PQntuples(res);
5373         *numOpfamilies = ntups;
5374
5375         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5376
5377         i_tableoid = PQfnumber(res, "tableoid");
5378         i_oid = PQfnumber(res, "oid");
5379         i_opfname = PQfnumber(res, "opfname");
5380         i_opfnamespace = PQfnumber(res, "opfnamespace");
5381         i_rolname = PQfnumber(res, "rolname");
5382
5383         for (i = 0; i < ntups; i++)
5384         {
5385                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5386                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5387                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5388                 AssignDumpId(&opfinfo[i].dobj);
5389                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5390                 opfinfo[i].dobj.namespace =
5391                         findNamespace(fout,
5392                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5393                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5394
5395                 /* Decide whether we want to dump it */
5396                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5397
5398                 /* Extensions do not currently have ACLs. */
5399                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5400
5401                 if (strlen(opfinfo[i].rolname) == 0)
5402                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5403                                           opfinfo[i].dobj.name);
5404         }
5405
5406         PQclear(res);
5407
5408         destroyPQExpBuffer(query);
5409
5410         return opfinfo;
5411 }
5412
5413 /*
5414  * getAggregates:
5415  *        read all the user-defined aggregates in the system catalogs and
5416  * return them in the AggInfo* structure
5417  *
5418  * numAggs is set to the number of aggregates read in
5419  */
5420 AggInfo *
5421 getAggregates(Archive *fout, int *numAggs)
5422 {
5423         DumpOptions *dopt = fout->dopt;
5424         PGresult   *res;
5425         int                     ntups;
5426         int                     i;
5427         PQExpBuffer query = createPQExpBuffer();
5428         AggInfo    *agginfo;
5429         int                     i_tableoid;
5430         int                     i_oid;
5431         int                     i_aggname;
5432         int                     i_aggnamespace;
5433         int                     i_pronargs;
5434         int                     i_proargtypes;
5435         int                     i_rolname;
5436         int                     i_aggacl;
5437         int                     i_raggacl;
5438         int                     i_initaggacl;
5439         int                     i_initraggacl;
5440
5441         /*
5442          * Find all interesting aggregates.  See comment in getFuncs() for the
5443          * rationale behind the filtering logic.
5444          */
5445         if (fout->remoteVersion >= 90600)
5446         {
5447                 PQExpBuffer acl_subquery = createPQExpBuffer();
5448                 PQExpBuffer racl_subquery = createPQExpBuffer();
5449                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5450                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5451                 const char *agg_check;
5452
5453                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5454                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5455                                                 dopt->binary_upgrade);
5456
5457                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5458                                          : "p.proisagg");
5459
5460                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5461                                                   "p.proname AS aggname, "
5462                                                   "p.pronamespace AS aggnamespace, "
5463                                                   "p.pronargs, p.proargtypes, "
5464                                                   "(%s p.proowner) AS rolname, "
5465                                                   "%s AS aggacl, "
5466                                                   "%s AS raggacl, "
5467                                                   "%s AS initaggacl, "
5468                                                   "%s AS initraggacl "
5469                                                   "FROM pg_proc p "
5470                                                   "LEFT JOIN pg_init_privs pip ON "
5471                                                   "(p.oid = pip.objoid "
5472                                                   "AND pip.classoid = 'pg_proc'::regclass "
5473                                                   "AND pip.objsubid = 0) "
5474                                                   "WHERE %s AND ("
5475                                                   "p.pronamespace != "
5476                                                   "(SELECT oid FROM pg_namespace "
5477                                                   "WHERE nspname = 'pg_catalog') OR "
5478                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5479                                                   username_subquery,
5480                                                   acl_subquery->data,
5481                                                   racl_subquery->data,
5482                                                   initacl_subquery->data,
5483                                                   initracl_subquery->data,
5484                                                   agg_check);
5485                 if (dopt->binary_upgrade)
5486                         appendPQExpBufferStr(query,
5487                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5488                                                                  "classid = 'pg_proc'::regclass AND "
5489                                                                  "objid = p.oid AND "
5490                                                                  "refclassid = 'pg_extension'::regclass AND "
5491                                                                  "deptype = 'e')");
5492                 appendPQExpBufferChar(query, ')');
5493
5494                 destroyPQExpBuffer(acl_subquery);
5495                 destroyPQExpBuffer(racl_subquery);
5496                 destroyPQExpBuffer(initacl_subquery);
5497                 destroyPQExpBuffer(initracl_subquery);
5498         }
5499         else if (fout->remoteVersion >= 80200)
5500         {
5501                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5502                                                   "pronamespace AS aggnamespace, "
5503                                                   "pronargs, proargtypes, "
5504                                                   "(%s proowner) AS rolname, "
5505                                                   "proacl AS aggacl, "
5506                                                   "NULL AS raggacl, "
5507                                                   "NULL AS initaggacl, NULL AS initraggacl "
5508                                                   "FROM pg_proc p "
5509                                                   "WHERE proisagg AND ("
5510                                                   "pronamespace != "
5511                                                   "(SELECT oid FROM pg_namespace "
5512                                                   "WHERE nspname = 'pg_catalog')",
5513                                                   username_subquery);
5514                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5515                         appendPQExpBufferStr(query,
5516                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5517                                                                  "classid = 'pg_proc'::regclass AND "
5518                                                                  "objid = p.oid AND "
5519                                                                  "refclassid = 'pg_extension'::regclass AND "
5520                                                                  "deptype = 'e')");
5521                 appendPQExpBufferChar(query, ')');
5522         }
5523         else
5524         {
5525                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5526                                                   "pronamespace AS aggnamespace, "
5527                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5528                                                   "proargtypes, "
5529                                                   "(%s proowner) AS rolname, "
5530                                                   "proacl AS aggacl, "
5531                                                   "NULL AS raggacl, "
5532                                                   "NULL AS initaggacl, NULL AS initraggacl "
5533                                                   "FROM pg_proc "
5534                                                   "WHERE proisagg "
5535                                                   "AND pronamespace != "
5536                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5537                                                   username_subquery);
5538         }
5539
5540         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5541
5542         ntups = PQntuples(res);
5543         *numAggs = ntups;
5544
5545         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5546
5547         i_tableoid = PQfnumber(res, "tableoid");
5548         i_oid = PQfnumber(res, "oid");
5549         i_aggname = PQfnumber(res, "aggname");
5550         i_aggnamespace = PQfnumber(res, "aggnamespace");
5551         i_pronargs = PQfnumber(res, "pronargs");
5552         i_proargtypes = PQfnumber(res, "proargtypes");
5553         i_rolname = PQfnumber(res, "rolname");
5554         i_aggacl = PQfnumber(res, "aggacl");
5555         i_raggacl = PQfnumber(res, "raggacl");
5556         i_initaggacl = PQfnumber(res, "initaggacl");
5557         i_initraggacl = PQfnumber(res, "initraggacl");
5558
5559         for (i = 0; i < ntups; i++)
5560         {
5561                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5562                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5563                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5564                 AssignDumpId(&agginfo[i].aggfn.dobj);
5565                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5566                 agginfo[i].aggfn.dobj.namespace =
5567                         findNamespace(fout,
5568                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5569                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5570                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5571                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5572                                           agginfo[i].aggfn.dobj.name);
5573                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5574                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5575                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5576                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5577                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5578                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5579                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5580                 if (agginfo[i].aggfn.nargs == 0)
5581                         agginfo[i].aggfn.argtypes = NULL;
5582                 else
5583                 {
5584                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5585                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5586                                                   agginfo[i].aggfn.argtypes,
5587                                                   agginfo[i].aggfn.nargs);
5588                 }
5589
5590                 /* Decide whether we want to dump it */
5591                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5592
5593                 /* Do not try to dump ACL if no ACL exists. */
5594                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5595                         PQgetisnull(res, i, i_initaggacl) &&
5596                         PQgetisnull(res, i, i_initraggacl))
5597                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5598         }
5599
5600         PQclear(res);
5601
5602         destroyPQExpBuffer(query);
5603
5604         return agginfo;
5605 }
5606
5607 /*
5608  * getFuncs:
5609  *        read all the user-defined functions in the system catalogs and
5610  * return them in the FuncInfo* structure
5611  *
5612  * numFuncs is set to the number of functions read in
5613  */
5614 FuncInfo *
5615 getFuncs(Archive *fout, int *numFuncs)
5616 {
5617         DumpOptions *dopt = fout->dopt;
5618         PGresult   *res;
5619         int                     ntups;
5620         int                     i;
5621         PQExpBuffer query = createPQExpBuffer();
5622         FuncInfo   *finfo;
5623         int                     i_tableoid;
5624         int                     i_oid;
5625         int                     i_proname;
5626         int                     i_pronamespace;
5627         int                     i_rolname;
5628         int                     i_prolang;
5629         int                     i_pronargs;
5630         int                     i_proargtypes;
5631         int                     i_prorettype;
5632         int                     i_proacl;
5633         int                     i_rproacl;
5634         int                     i_initproacl;
5635         int                     i_initrproacl;
5636
5637         /*
5638          * Find all interesting functions.  This is a bit complicated:
5639          *
5640          * 1. Always exclude aggregates; those are handled elsewhere.
5641          *
5642          * 2. Always exclude functions that are internally dependent on something
5643          * else, since presumably those will be created as a result of creating
5644          * the something else.  This currently acts only to suppress constructor
5645          * functions for range types (so we only need it in 9.2 and up).  Note
5646          * this is OK only because the constructors don't have any dependencies
5647          * the range type doesn't have; otherwise we might not get creation
5648          * ordering correct.
5649          *
5650          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5651          * they're members of extensions and we are in binary-upgrade mode then
5652          * include them, since we want to dump extension members individually in
5653          * that mode.  Also, if they are used by casts or transforms then we need
5654          * to gather the information about them, though they won't be dumped if
5655          * they are built-in.  Also, in 9.6 and up, include functions in
5656          * pg_catalog if they have an ACL different from what's shown in
5657          * pg_init_privs.
5658          */
5659         if (fout->remoteVersion >= 90600)
5660         {
5661                 PQExpBuffer acl_subquery = createPQExpBuffer();
5662                 PQExpBuffer racl_subquery = createPQExpBuffer();
5663                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5664                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5665                 const char *not_agg_check;
5666
5667                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5668                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5669                                                 dopt->binary_upgrade);
5670
5671                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5672                                                  : "NOT p.proisagg");
5673
5674                 appendPQExpBuffer(query,
5675                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5676                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5677                                                   "%s AS proacl, "
5678                                                   "%s AS rproacl, "
5679                                                   "%s AS initproacl, "
5680                                                   "%s AS initrproacl, "
5681                                                   "p.pronamespace, "
5682                                                   "(%s p.proowner) AS rolname "
5683                                                   "FROM pg_proc p "
5684                                                   "LEFT JOIN pg_init_privs pip ON "
5685                                                   "(p.oid = pip.objoid "
5686                                                   "AND pip.classoid = 'pg_proc'::regclass "
5687                                                   "AND pip.objsubid = 0) "
5688                                                   "WHERE %s"
5689                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5690                                                   "WHERE classid = 'pg_proc'::regclass AND "
5691                                                   "objid = p.oid AND deptype = 'i')"
5692                                                   "\n  AND ("
5693                                                   "\n  pronamespace != "
5694                                                   "(SELECT oid FROM pg_namespace "
5695                                                   "WHERE nspname = 'pg_catalog')"
5696                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5697                                                   "\n  WHERE pg_cast.oid > %u "
5698                                                   "\n  AND p.oid = pg_cast.castfunc)"
5699                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5700                                                   "\n  WHERE pg_transform.oid > %u AND "
5701                                                   "\n  (p.oid = pg_transform.trffromsql"
5702                                                   "\n  OR p.oid = pg_transform.trftosql))",
5703                                                   acl_subquery->data,
5704                                                   racl_subquery->data,
5705                                                   initacl_subquery->data,
5706                                                   initracl_subquery->data,
5707                                                   username_subquery,
5708                                                   not_agg_check,
5709                                                   g_last_builtin_oid,
5710                                                   g_last_builtin_oid);
5711                 if (dopt->binary_upgrade)
5712                         appendPQExpBufferStr(query,
5713                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5714                                                                  "classid = 'pg_proc'::regclass AND "
5715                                                                  "objid = p.oid AND "
5716                                                                  "refclassid = 'pg_extension'::regclass AND "
5717                                                                  "deptype = 'e')");
5718                 appendPQExpBufferStr(query,
5719                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5720                 appendPQExpBufferChar(query, ')');
5721
5722                 destroyPQExpBuffer(acl_subquery);
5723                 destroyPQExpBuffer(racl_subquery);
5724                 destroyPQExpBuffer(initacl_subquery);
5725                 destroyPQExpBuffer(initracl_subquery);
5726         }
5727         else
5728         {
5729                 appendPQExpBuffer(query,
5730                                                   "SELECT tableoid, oid, proname, prolang, "
5731                                                   "pronargs, proargtypes, prorettype, proacl, "
5732                                                   "NULL as rproacl, "
5733                                                   "NULL as initproacl, NULL AS initrproacl, "
5734                                                   "pronamespace, "
5735                                                   "(%s proowner) AS rolname "
5736                                                   "FROM pg_proc p "
5737                                                   "WHERE NOT proisagg",
5738                                                   username_subquery);
5739                 if (fout->remoteVersion >= 90200)
5740                         appendPQExpBufferStr(query,
5741                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5742                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5743                                                                  "objid = p.oid AND deptype = 'i')");
5744                 appendPQExpBuffer(query,
5745                                                   "\n  AND ("
5746                                                   "\n  pronamespace != "
5747                                                   "(SELECT oid FROM pg_namespace "
5748                                                   "WHERE nspname = 'pg_catalog')"
5749                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5750                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5751                                                   "\n  AND p.oid = pg_cast.castfunc)",
5752                                                   g_last_builtin_oid);
5753
5754                 if (fout->remoteVersion >= 90500)
5755                         appendPQExpBuffer(query,
5756                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5757                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5758                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5759                                                           "\n  OR p.oid = pg_transform.trftosql))",
5760                                                           g_last_builtin_oid);
5761
5762                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5763                         appendPQExpBufferStr(query,
5764                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5765                                                                  "classid = 'pg_proc'::regclass AND "
5766                                                                  "objid = p.oid AND "
5767                                                                  "refclassid = 'pg_extension'::regclass AND "
5768                                                                  "deptype = 'e')");
5769                 appendPQExpBufferChar(query, ')');
5770         }
5771
5772         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5773
5774         ntups = PQntuples(res);
5775
5776         *numFuncs = ntups;
5777
5778         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5779
5780         i_tableoid = PQfnumber(res, "tableoid");
5781         i_oid = PQfnumber(res, "oid");
5782         i_proname = PQfnumber(res, "proname");
5783         i_pronamespace = PQfnumber(res, "pronamespace");
5784         i_rolname = PQfnumber(res, "rolname");
5785         i_prolang = PQfnumber(res, "prolang");
5786         i_pronargs = PQfnumber(res, "pronargs");
5787         i_proargtypes = PQfnumber(res, "proargtypes");
5788         i_prorettype = PQfnumber(res, "prorettype");
5789         i_proacl = PQfnumber(res, "proacl");
5790         i_rproacl = PQfnumber(res, "rproacl");
5791         i_initproacl = PQfnumber(res, "initproacl");
5792         i_initrproacl = PQfnumber(res, "initrproacl");
5793
5794         for (i = 0; i < ntups; i++)
5795         {
5796                 finfo[i].dobj.objType = DO_FUNC;
5797                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5798                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5799                 AssignDumpId(&finfo[i].dobj);
5800                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5801                 finfo[i].dobj.namespace =
5802                         findNamespace(fout,
5803                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5804                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5805                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5806                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5807                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5808                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5809                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5810                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5811                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5812                 if (finfo[i].nargs == 0)
5813                         finfo[i].argtypes = NULL;
5814                 else
5815                 {
5816                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5817                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5818                                                   finfo[i].argtypes, finfo[i].nargs);
5819                 }
5820
5821                 /* Decide whether we want to dump it */
5822                 selectDumpableObject(&(finfo[i].dobj), fout);
5823
5824                 /* Do not try to dump ACL if no ACL exists. */
5825                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5826                         PQgetisnull(res, i, i_initproacl) &&
5827                         PQgetisnull(res, i, i_initrproacl))
5828                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5829
5830                 if (strlen(finfo[i].rolname) == 0)
5831                         write_msg(NULL,
5832                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5833                                           finfo[i].dobj.name);
5834         }
5835
5836         PQclear(res);
5837
5838         destroyPQExpBuffer(query);
5839
5840         return finfo;
5841 }
5842
5843 /*
5844  * getTables
5845  *        read all the tables (no indexes)
5846  * in the system catalogs return them in the TableInfo* structure
5847  *
5848  * numTables is set to the number of tables read in
5849  */
5850 TableInfo *
5851 getTables(Archive *fout, int *numTables)
5852 {
5853         DumpOptions *dopt = fout->dopt;
5854         PGresult   *res;
5855         int                     ntups;
5856         int                     i;
5857         PQExpBuffer query = createPQExpBuffer();
5858         TableInfo  *tblinfo;
5859         int                     i_reltableoid;
5860         int                     i_reloid;
5861         int                     i_relname;
5862         int                     i_relnamespace;
5863         int                     i_relkind;
5864         int                     i_relacl;
5865         int                     i_rrelacl;
5866         int                     i_initrelacl;
5867         int                     i_initrrelacl;
5868         int                     i_rolname;
5869         int                     i_relchecks;
5870         int                     i_relhastriggers;
5871         int                     i_relhasindex;
5872         int                     i_relhasrules;
5873         int                     i_relrowsec;
5874         int                     i_relforcerowsec;
5875         int                     i_relhasoids;
5876         int                     i_relfrozenxid;
5877         int                     i_relminmxid;
5878         int                     i_toastoid;
5879         int                     i_toastfrozenxid;
5880         int                     i_toastminmxid;
5881         int                     i_relpersistence;
5882         int                     i_relispopulated;
5883         int                     i_relreplident;
5884         int                     i_owning_tab;
5885         int                     i_owning_col;
5886         int                     i_reltablespace;
5887         int                     i_reloptions;
5888         int                     i_checkoption;
5889         int                     i_toastreloptions;
5890         int                     i_reloftype;
5891         int                     i_relpages;
5892         int                     i_is_identity_sequence;
5893         int                     i_changed_acl;
5894         int                     i_partkeydef;
5895         int                     i_ispartition;
5896         int                     i_partbound;
5897
5898         /*
5899          * Find all the tables and table-like objects.
5900          *
5901          * We include system catalogs, so that we can work if a user table is
5902          * defined to inherit from a system catalog (pretty weird, but...)
5903          *
5904          * We ignore relations that are not ordinary tables, sequences, views,
5905          * materialized views, composite types, or foreign tables.
5906          *
5907          * Composite-type table entries won't be dumped as such, but we have to
5908          * make a DumpableObject for them so that we can track dependencies of the
5909          * composite type (pg_depend entries for columns of the composite type
5910          * link to the pg_class entry not the pg_type entry).
5911          *
5912          * Note: in this phase we should collect only a minimal amount of
5913          * information about each table, basically just enough to decide if it is
5914          * interesting. We must fetch all tables in this phase because otherwise
5915          * we cannot correctly identify inherited columns, owned sequences, etc.
5916          */
5917
5918         if (fout->remoteVersion >= 90600)
5919         {
5920                 char       *partkeydef = "NULL";
5921                 char       *ispartition = "false";
5922                 char       *partbound = "NULL";
5923
5924                 PQExpBuffer acl_subquery = createPQExpBuffer();
5925                 PQExpBuffer racl_subquery = createPQExpBuffer();
5926                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5927                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5928
5929                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5930                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5931                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5932                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5933
5934                 /*
5935                  * Collect the information about any partitioned tables, which were
5936                  * added in PG10.
5937                  */
5938
5939                 if (fout->remoteVersion >= 100000)
5940                 {
5941                         partkeydef = "pg_get_partkeydef(c.oid)";
5942                         ispartition = "c.relispartition";
5943                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5944                 }
5945
5946                 /*
5947                  * Left join to pick up dependency info linking sequences to their
5948                  * owning column, if any (note this dependency is AUTO as of 8.2)
5949                  *
5950                  * Left join to detect if any privileges are still as-set-at-init, in
5951                  * which case we won't dump out ACL commands for those.
5952                  */
5953
5954                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5955                                                 initracl_subquery, "c.relacl", "c.relowner",
5956                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5957                                                 " THEN 's' ELSE 'r' END::\"char\"",
5958                                                 dopt->binary_upgrade);
5959
5960                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5961                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5962                                                 dopt->binary_upgrade);
5963
5964                 appendPQExpBuffer(query,
5965                                                   "SELECT c.tableoid, c.oid, c.relname, "
5966                                                   "%s AS relacl, %s as rrelacl, "
5967                                                   "%s AS initrelacl, %s as initrrelacl, "
5968                                                   "c.relkind, c.relnamespace, "
5969                                                   "(%s c.relowner) AS rolname, "
5970                                                   "c.relchecks, c.relhastriggers, "
5971                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
5972                                                   "c.relrowsecurity, c.relforcerowsecurity, "
5973                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5974                                                   "tc.relfrozenxid AS tfrozenxid, "
5975                                                   "tc.relminmxid AS tminmxid, "
5976                                                   "c.relpersistence, c.relispopulated, "
5977                                                   "c.relreplident, c.relpages, "
5978                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5979                                                   "d.refobjid AS owning_tab, "
5980                                                   "d.refobjsubid AS owning_col, "
5981                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5982                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5983                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5984                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5985                                                   "tc.reloptions AS toast_reloptions, "
5986                                                   "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, "
5987                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5988                                                   "(c.oid = pip.objoid "
5989                                                   "AND pip.classoid = 'pg_class'::regclass "
5990                                                   "AND pip.objsubid = at.attnum)"
5991                                                   "WHERE at.attrelid = c.oid AND ("
5992                                                   "%s IS NOT NULL "
5993                                                   "OR %s IS NOT NULL "
5994                                                   "OR %s IS NOT NULL "
5995                                                   "OR %s IS NOT NULL"
5996                                                   "))"
5997                                                   "AS changed_acl, "
5998                                                   "%s AS partkeydef, "
5999                                                   "%s AS ispartition, "
6000                                                   "%s AS partbound "
6001                                                   "FROM pg_class c "
6002                                                   "LEFT JOIN pg_depend d ON "
6003                                                   "(c.relkind = '%c' AND "
6004                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6005                                                   "d.objsubid = 0 AND "
6006                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6007                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6008                                                   "LEFT JOIN pg_init_privs pip ON "
6009                                                   "(c.oid = pip.objoid "
6010                                                   "AND pip.classoid = 'pg_class'::regclass "
6011                                                   "AND pip.objsubid = 0) "
6012                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6013                                                   "ORDER BY c.oid",
6014                                                   acl_subquery->data,
6015                                                   racl_subquery->data,
6016                                                   initacl_subquery->data,
6017                                                   initracl_subquery->data,
6018                                                   username_subquery,
6019                                                   RELKIND_SEQUENCE,
6020                                                   attacl_subquery->data,
6021                                                   attracl_subquery->data,
6022                                                   attinitacl_subquery->data,
6023                                                   attinitracl_subquery->data,
6024                                                   partkeydef,
6025                                                   ispartition,
6026                                                   partbound,
6027                                                   RELKIND_SEQUENCE,
6028                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6029                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6030                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6031                                                   RELKIND_PARTITIONED_TABLE);
6032
6033                 destroyPQExpBuffer(acl_subquery);
6034                 destroyPQExpBuffer(racl_subquery);
6035                 destroyPQExpBuffer(initacl_subquery);
6036                 destroyPQExpBuffer(initracl_subquery);
6037
6038                 destroyPQExpBuffer(attacl_subquery);
6039                 destroyPQExpBuffer(attracl_subquery);
6040                 destroyPQExpBuffer(attinitacl_subquery);
6041                 destroyPQExpBuffer(attinitracl_subquery);
6042         }
6043         else if (fout->remoteVersion >= 90500)
6044         {
6045                 /*
6046                  * Left join to pick up dependency info linking sequences to their
6047                  * owning column, if any (note this dependency is AUTO as of 8.2)
6048                  */
6049                 appendPQExpBuffer(query,
6050                                                   "SELECT c.tableoid, c.oid, c.relname, "
6051                                                   "c.relacl, NULL as rrelacl, "
6052                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6053                                                   "c.relkind, "
6054                                                   "c.relnamespace, "
6055                                                   "(%s c.relowner) AS rolname, "
6056                                                   "c.relchecks, c.relhastriggers, "
6057                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6058                                                   "c.relrowsecurity, c.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 >= 90400)
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                                                   "c.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 >= 90300)
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, c.relminmxid, tc.oid AS toid, "
6158                                                   "tc.relfrozenxid AS tfrozenxid, "
6159                                                   "tc.relminmxid AS tminmxid, "
6160                                                   "c.relpersistence, c.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                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6167                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6168                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6169                                                   "tc.reloptions AS toast_reloptions, "
6170                                                   "NULL AS changed_acl, "
6171                                                   "NULL AS partkeydef, "
6172                                                   "false AS ispartition, "
6173                                                   "NULL AS partbound "
6174                                                   "FROM pg_class c "
6175                                                   "LEFT JOIN pg_depend d ON "
6176                                                   "(c.relkind = '%c' AND "
6177                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6178                                                   "d.objsubid = 0 AND "
6179                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6180                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6181                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6182                                                   "ORDER BY c.oid",
6183                                                   username_subquery,
6184                                                   RELKIND_SEQUENCE,
6185                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6186                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6187                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6188         }
6189         else if (fout->remoteVersion >= 90100)
6190         {
6191                 /*
6192                  * Left join to pick up dependency info linking sequences to their
6193                  * owning column, if any (note this dependency is AUTO as of 8.2)
6194                  */
6195                 appendPQExpBuffer(query,
6196                                                   "SELECT c.tableoid, c.oid, c.relname, "
6197                                                   "c.relacl, NULL as rrelacl, "
6198                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6199                                                   "c.relkind, "
6200                                                   "c.relnamespace, "
6201                                                   "(%s c.relowner) AS rolname, "
6202                                                   "c.relchecks, c.relhastriggers, "
6203                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6204                                                   "'f'::bool AS relrowsecurity, "
6205                                                   "'f'::bool AS relforcerowsecurity, "
6206                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6207                                                   "tc.relfrozenxid AS tfrozenxid, "
6208                                                   "0 AS tminmxid, "
6209                                                   "c.relpersistence, 't' as relispopulated, "
6210                                                   "'d' AS relreplident, c.relpages, "
6211                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6212                                                   "d.refobjid AS owning_tab, "
6213                                                   "d.refobjsubid AS owning_col, "
6214                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6215                                                   "c.reloptions AS reloptions, "
6216                                                   "tc.reloptions AS toast_reloptions, "
6217                                                   "NULL AS changed_acl, "
6218                                                   "NULL AS partkeydef, "
6219                                                   "false AS ispartition, "
6220                                                   "NULL AS partbound "
6221                                                   "FROM pg_class c "
6222                                                   "LEFT JOIN pg_depend d ON "
6223                                                   "(c.relkind = '%c' AND "
6224                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6225                                                   "d.objsubid = 0 AND "
6226                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6227                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6228                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6229                                                   "ORDER BY c.oid",
6230                                                   username_subquery,
6231                                                   RELKIND_SEQUENCE,
6232                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6233                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6234                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6235         }
6236         else if (fout->remoteVersion >= 90000)
6237         {
6238                 /*
6239                  * Left join to pick up dependency info linking sequences to their
6240                  * owning column, if any (note this dependency is AUTO as of 8.2)
6241                  */
6242                 appendPQExpBuffer(query,
6243                                                   "SELECT c.tableoid, c.oid, c.relname, "
6244                                                   "c.relacl, NULL as rrelacl, "
6245                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6246                                                   "c.relkind, "
6247                                                   "c.relnamespace, "
6248                                                   "(%s c.relowner) AS rolname, "
6249                                                   "c.relchecks, c.relhastriggers, "
6250                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6251                                                   "'f'::bool AS relrowsecurity, "
6252                                                   "'f'::bool AS relforcerowsecurity, "
6253                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6254                                                   "tc.relfrozenxid AS tfrozenxid, "
6255                                                   "0 AS tminmxid, "
6256                                                   "'p' AS relpersistence, 't' as relispopulated, "
6257                                                   "'d' AS relreplident, c.relpages, "
6258                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6259                                                   "d.refobjid AS owning_tab, "
6260                                                   "d.refobjsubid AS owning_col, "
6261                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6262                                                   "c.reloptions AS reloptions, "
6263                                                   "tc.reloptions AS toast_reloptions, "
6264                                                   "NULL AS changed_acl, "
6265                                                   "NULL AS partkeydef, "
6266                                                   "false AS ispartition, "
6267                                                   "NULL AS partbound "
6268                                                   "FROM pg_class c "
6269                                                   "LEFT JOIN pg_depend d ON "
6270                                                   "(c.relkind = '%c' AND "
6271                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6272                                                   "d.objsubid = 0 AND "
6273                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6274                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6275                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6276                                                   "ORDER BY c.oid",
6277                                                   username_subquery,
6278                                                   RELKIND_SEQUENCE,
6279                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6280                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6281         }
6282         else if (fout->remoteVersion >= 80400)
6283         {
6284                 /*
6285                  * Left join to pick up dependency info linking sequences to their
6286                  * owning column, if any (note this dependency is AUTO as of 8.2)
6287                  */
6288                 appendPQExpBuffer(query,
6289                                                   "SELECT c.tableoid, c.oid, c.relname, "
6290                                                   "c.relacl, NULL as rrelacl, "
6291                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6292                                                   "c.relkind, "
6293                                                   "c.relnamespace, "
6294                                                   "(%s c.relowner) AS rolname, "
6295                                                   "c.relchecks, c.relhastriggers, "
6296                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6297                                                   "'f'::bool AS relrowsecurity, "
6298                                                   "'f'::bool AS relforcerowsecurity, "
6299                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6300                                                   "tc.relfrozenxid AS tfrozenxid, "
6301                                                   "0 AS tminmxid, "
6302                                                   "'p' AS relpersistence, 't' as relispopulated, "
6303                                                   "'d' AS relreplident, c.relpages, "
6304                                                   "NULL AS reloftype, "
6305                                                   "d.refobjid AS owning_tab, "
6306                                                   "d.refobjsubid AS owning_col, "
6307                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6308                                                   "c.reloptions AS reloptions, "
6309                                                   "tc.reloptions AS toast_reloptions, "
6310                                                   "NULL AS changed_acl, "
6311                                                   "NULL AS partkeydef, "
6312                                                   "false AS ispartition, "
6313                                                   "NULL AS partbound "
6314                                                   "FROM pg_class c "
6315                                                   "LEFT JOIN pg_depend d ON "
6316                                                   "(c.relkind = '%c' AND "
6317                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6318                                                   "d.objsubid = 0 AND "
6319                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6320                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6321                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6322                                                   "ORDER BY c.oid",
6323                                                   username_subquery,
6324                                                   RELKIND_SEQUENCE,
6325                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6326                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6327         }
6328         else if (fout->remoteVersion >= 80200)
6329         {
6330                 /*
6331                  * Left join to pick up dependency info linking sequences to their
6332                  * owning column, if any (note this dependency is AUTO as of 8.2)
6333                  */
6334                 appendPQExpBuffer(query,
6335                                                   "SELECT c.tableoid, c.oid, c.relname, "
6336                                                   "c.relacl, NULL as rrelacl, "
6337                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6338                                                   "c.relkind, "
6339                                                   "c.relnamespace, "
6340                                                   "(%s c.relowner) AS rolname, "
6341                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6342                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6343                                                   "'f'::bool AS relrowsecurity, "
6344                                                   "'f'::bool AS relforcerowsecurity, "
6345                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6346                                                   "tc.relfrozenxid AS tfrozenxid, "
6347                                                   "0 AS tminmxid, "
6348                                                   "'p' AS relpersistence, 't' as relispopulated, "
6349                                                   "'d' AS relreplident, c.relpages, "
6350                                                   "NULL AS reloftype, "
6351                                                   "d.refobjid AS owning_tab, "
6352                                                   "d.refobjsubid AS owning_col, "
6353                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6354                                                   "c.reloptions AS reloptions, "
6355                                                   "NULL AS toast_reloptions, "
6356                                                   "NULL AS changed_acl, "
6357                                                   "NULL AS partkeydef, "
6358                                                   "false AS ispartition, "
6359                                                   "NULL AS partbound "
6360                                                   "FROM pg_class c "
6361                                                   "LEFT JOIN pg_depend d ON "
6362                                                   "(c.relkind = '%c' AND "
6363                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6364                                                   "d.objsubid = 0 AND "
6365                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6366                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6367                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6368                                                   "ORDER BY c.oid",
6369                                                   username_subquery,
6370                                                   RELKIND_SEQUENCE,
6371                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6372                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6373         }
6374         else
6375         {
6376                 /*
6377                  * Left join to pick up dependency info linking sequences to their
6378                  * owning column, if any
6379                  */
6380                 appendPQExpBuffer(query,
6381                                                   "SELECT c.tableoid, c.oid, relname, "
6382                                                   "relacl, NULL as rrelacl, "
6383                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6384                                                   "relkind, relnamespace, "
6385                                                   "(%s relowner) AS rolname, "
6386                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6387                                                   "relhasindex, relhasrules, relhasoids, "
6388                                                   "'f'::bool AS relrowsecurity, "
6389                                                   "'f'::bool AS relforcerowsecurity, "
6390                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6391                                                   "0 AS toid, "
6392                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6393                                                   "'p' AS relpersistence, 't' as relispopulated, "
6394                                                   "'d' AS relreplident, relpages, "
6395                                                   "NULL AS reloftype, "
6396                                                   "d.refobjid AS owning_tab, "
6397                                                   "d.refobjsubid AS owning_col, "
6398                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6399                                                   "NULL AS reloptions, "
6400                                                   "NULL AS toast_reloptions, "
6401                                                   "NULL AS changed_acl, "
6402                                                   "NULL AS partkeydef, "
6403                                                   "false AS ispartition, "
6404                                                   "NULL AS partbound "
6405                                                   "FROM pg_class c "
6406                                                   "LEFT JOIN pg_depend d ON "
6407                                                   "(c.relkind = '%c' AND "
6408                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6409                                                   "d.objsubid = 0 AND "
6410                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6411                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6412                                                   "ORDER BY c.oid",
6413                                                   username_subquery,
6414                                                   RELKIND_SEQUENCE,
6415                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6416                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6417         }
6418
6419         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6420
6421         ntups = PQntuples(res);
6422
6423         *numTables = ntups;
6424
6425         /*
6426          * Extract data from result and lock dumpable tables.  We do the locking
6427          * before anything else, to minimize the window wherein a table could
6428          * disappear under us.
6429          *
6430          * Note that we have to save info about all tables here, even when dumping
6431          * only one, because we don't yet know which tables might be inheritance
6432          * ancestors of the target table.
6433          */
6434         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6435
6436         i_reltableoid = PQfnumber(res, "tableoid");
6437         i_reloid = PQfnumber(res, "oid");
6438         i_relname = PQfnumber(res, "relname");
6439         i_relnamespace = PQfnumber(res, "relnamespace");
6440         i_relacl = PQfnumber(res, "relacl");
6441         i_rrelacl = PQfnumber(res, "rrelacl");
6442         i_initrelacl = PQfnumber(res, "initrelacl");
6443         i_initrrelacl = PQfnumber(res, "initrrelacl");
6444         i_relkind = PQfnumber(res, "relkind");
6445         i_rolname = PQfnumber(res, "rolname");
6446         i_relchecks = PQfnumber(res, "relchecks");
6447         i_relhastriggers = PQfnumber(res, "relhastriggers");
6448         i_relhasindex = PQfnumber(res, "relhasindex");
6449         i_relhasrules = PQfnumber(res, "relhasrules");
6450         i_relrowsec = PQfnumber(res, "relrowsecurity");
6451         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6452         i_relhasoids = PQfnumber(res, "relhasoids");
6453         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6454         i_relminmxid = PQfnumber(res, "relminmxid");
6455         i_toastoid = PQfnumber(res, "toid");
6456         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6457         i_toastminmxid = PQfnumber(res, "tminmxid");
6458         i_relpersistence = PQfnumber(res, "relpersistence");
6459         i_relispopulated = PQfnumber(res, "relispopulated");
6460         i_relreplident = PQfnumber(res, "relreplident");
6461         i_relpages = PQfnumber(res, "relpages");
6462         i_owning_tab = PQfnumber(res, "owning_tab");
6463         i_owning_col = PQfnumber(res, "owning_col");
6464         i_reltablespace = PQfnumber(res, "reltablespace");
6465         i_reloptions = PQfnumber(res, "reloptions");
6466         i_checkoption = PQfnumber(res, "checkoption");
6467         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6468         i_reloftype = PQfnumber(res, "reloftype");
6469         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6470         i_changed_acl = PQfnumber(res, "changed_acl");
6471         i_partkeydef = PQfnumber(res, "partkeydef");
6472         i_ispartition = PQfnumber(res, "ispartition");
6473         i_partbound = PQfnumber(res, "partbound");
6474
6475         if (dopt->lockWaitTimeout)
6476         {
6477                 /*
6478                  * Arrange to fail instead of waiting forever for a table lock.
6479                  *
6480                  * NB: this coding assumes that the only queries issued within the
6481                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6482                  * applied to other things too.
6483                  */
6484                 resetPQExpBuffer(query);
6485                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6486                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6487                 ExecuteSqlStatement(fout, query->data);
6488         }
6489
6490         for (i = 0; i < ntups; i++)
6491         {
6492                 tblinfo[i].dobj.objType = DO_TABLE;
6493                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6494                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6495                 AssignDumpId(&tblinfo[i].dobj);
6496                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6497                 tblinfo[i].dobj.namespace =
6498                         findNamespace(fout,
6499                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6500                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6501                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6502                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6503                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6504                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6505                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6506                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6507                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6508                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6509                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6510                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6511                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6512                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6513                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6514                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6515                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6516                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6517                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6518                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6519                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6520                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6521                 if (PQgetisnull(res, i, i_reloftype))
6522                         tblinfo[i].reloftype = NULL;
6523                 else
6524                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6525                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6526                 if (PQgetisnull(res, i, i_owning_tab))
6527                 {
6528                         tblinfo[i].owning_tab = InvalidOid;
6529                         tblinfo[i].owning_col = 0;
6530                 }
6531                 else
6532                 {
6533                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6534                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6535                 }
6536                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6537                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6538                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6539                         tblinfo[i].checkoption = NULL;
6540                 else
6541                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6542                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6543
6544                 /* other fields were zeroed above */
6545
6546                 /*
6547                  * Decide whether we want to dump this table.
6548                  */
6549                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6550                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6551                 else
6552                         selectDumpableTable(&tblinfo[i], fout);
6553
6554                 /*
6555                  * If the table-level and all column-level ACLs for this table are
6556                  * unchanged, then we don't need to worry about including the ACLs for
6557                  * this table.  If any column-level ACLs have been changed, the
6558                  * 'changed_acl' column from the query will indicate that.
6559                  *
6560                  * This can result in a significant performance improvement in cases
6561                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6562                  */
6563                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6564                         PQgetisnull(res, i, i_initrelacl) &&
6565                         PQgetisnull(res, i, i_initrrelacl) &&
6566                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6567                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6568
6569                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6570                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6571                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6572
6573                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6574                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6575
6576                 /* Partition key string or NULL */
6577                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6578                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6579                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6580
6581                 /*
6582                  * Read-lock target tables to make sure they aren't DROPPED or altered
6583                  * in schema before we get around to dumping them.
6584                  *
6585                  * Note that we don't explicitly lock parents of the target tables; we
6586                  * assume our lock on the child is enough to prevent schema
6587                  * alterations to parent tables.
6588                  *
6589                  * NOTE: it'd be kinda nice to lock other relations too, not only
6590                  * plain or partitioned tables, but the backend doesn't presently
6591                  * allow that.
6592                  *
6593                  * We only need to lock the table for certain components; see
6594                  * pg_dump.h
6595                  */
6596                 if (tblinfo[i].dobj.dump &&
6597                         (tblinfo[i].relkind == RELKIND_RELATION ||
6598                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6599                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6600                 {
6601                         resetPQExpBuffer(query);
6602                         appendPQExpBuffer(query,
6603                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6604                                                           fmtQualifiedDumpable(&tblinfo[i]));
6605                         ExecuteSqlStatement(fout, query->data);
6606                 }
6607
6608                 /* Emit notice if join for owner failed */
6609                 if (strlen(tblinfo[i].rolname) == 0)
6610                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6611                                           tblinfo[i].dobj.name);
6612         }
6613
6614         if (dopt->lockWaitTimeout)
6615         {
6616                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6617         }
6618
6619         PQclear(res);
6620
6621         destroyPQExpBuffer(query);
6622
6623         return tblinfo;
6624 }
6625
6626 /*
6627  * getOwnedSeqs
6628  *        identify owned sequences and mark them as dumpable if owning table is
6629  *
6630  * We used to do this in getTables(), but it's better to do it after the
6631  * index used by findTableByOid() has been set up.
6632  */
6633 void
6634 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6635 {
6636         int                     i;
6637
6638         /*
6639          * Force sequences that are "owned" by table columns to be dumped whenever
6640          * their owning table is being dumped.
6641          */
6642         for (i = 0; i < numTables; i++)
6643         {
6644                 TableInfo  *seqinfo = &tblinfo[i];
6645                 TableInfo  *owning_tab;
6646
6647                 if (!OidIsValid(seqinfo->owning_tab))
6648                         continue;                       /* not an owned sequence */
6649
6650                 owning_tab = findTableByOid(seqinfo->owning_tab);
6651                 if (owning_tab == NULL)
6652                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6653                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6654
6655                 /*
6656                  * Only dump identity sequences if we're going to dump the table that
6657                  * it belongs to.
6658                  */
6659                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6660                         seqinfo->is_identity_sequence)
6661                 {
6662                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6663                         continue;
6664                 }
6665
6666                 /*
6667                  * Otherwise we need to dump the components that are being dumped for
6668                  * the table and any components which the sequence is explicitly
6669                  * marked with.
6670                  *
6671                  * We can't simply use the set of components which are being dumped
6672                  * for the table as the table might be in an extension (and only the
6673                  * non-extension components, eg: ACLs if changed, security labels, and
6674                  * policies, are being dumped) while the sequence is not (and
6675                  * therefore the definition and other components should also be
6676                  * dumped).
6677                  *
6678                  * If the sequence is part of the extension then it should be properly
6679                  * marked by checkExtensionMembership() and this will be a no-op as
6680                  * the table will be equivalently marked.
6681                  */
6682                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6683
6684                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6685                         seqinfo->interesting = true;
6686         }
6687 }
6688
6689 /*
6690  * getInherits
6691  *        read all the inheritance information
6692  * from the system catalogs return them in the InhInfo* structure
6693  *
6694  * numInherits is set to the number of pairs read in
6695  */
6696 InhInfo *
6697 getInherits(Archive *fout, int *numInherits)
6698 {
6699         PGresult   *res;
6700         int                     ntups;
6701         int                     i;
6702         PQExpBuffer query = createPQExpBuffer();
6703         InhInfo    *inhinfo;
6704
6705         int                     i_inhrelid;
6706         int                     i_inhparent;
6707
6708         /*
6709          * Find all the inheritance information, excluding implicit inheritance
6710          * via partitioning.  We handle that case using getPartitions(), because
6711          * we want more information about partitions than just the parent-child
6712          * relationship.
6713          */
6714         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6715
6716         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6717
6718         ntups = PQntuples(res);
6719
6720         *numInherits = ntups;
6721
6722         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6723
6724         i_inhrelid = PQfnumber(res, "inhrelid");
6725         i_inhparent = PQfnumber(res, "inhparent");
6726
6727         for (i = 0; i < ntups; i++)
6728         {
6729                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6730                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6731         }
6732
6733         PQclear(res);
6734
6735         destroyPQExpBuffer(query);
6736
6737         return inhinfo;
6738 }
6739
6740 /*
6741  * getIndexes
6742  *        get information about every index on a dumpable table
6743  *
6744  * Note: index data is not returned directly to the caller, but it
6745  * does get entered into the DumpableObject tables.
6746  */
6747 void
6748 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6749 {
6750         int                     i,
6751                                 j;
6752         PQExpBuffer query = createPQExpBuffer();
6753         PGresult   *res;
6754         IndxInfo   *indxinfo;
6755         ConstraintInfo *constrinfo;
6756         int                     i_tableoid,
6757                                 i_oid,
6758                                 i_indexname,
6759                                 i_parentidx,
6760                                 i_indexdef,
6761                                 i_indnkeyatts,
6762                                 i_indnatts,
6763                                 i_indkey,
6764                                 i_indisclustered,
6765                                 i_indisreplident,
6766                                 i_contype,
6767                                 i_conname,
6768                                 i_condeferrable,
6769                                 i_condeferred,
6770                                 i_contableoid,
6771                                 i_conoid,
6772                                 i_condef,
6773                                 i_tablespace,
6774                                 i_indreloptions;
6775         int                     ntups;
6776
6777         for (i = 0; i < numTables; i++)
6778         {
6779                 TableInfo  *tbinfo = &tblinfo[i];
6780
6781                 if (!tbinfo->hasindex)
6782                         continue;
6783
6784                 /*
6785                  * Ignore indexes of tables whose definitions are not to be dumped.
6786                  *
6787                  * We also need indexes on partitioned tables which have partitions to
6788                  * be dumped, in order to dump the indexes on the partitions.
6789                  */
6790                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6791                         !tbinfo->interesting)
6792                         continue;
6793
6794                 if (g_verbose)
6795                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6796                                           tbinfo->dobj.namespace->dobj.name,
6797                                           tbinfo->dobj.name);
6798
6799                 /*
6800                  * The point of the messy-looking outer join is to find a constraint
6801                  * that is related by an internal dependency link to the index. If we
6802                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6803                  * assume an index won't have more than one internal dependency.
6804                  *
6805                  * As of 9.0 we don't need to look at pg_depend but can check for a
6806                  * match to pg_constraint.conindid.  The check on conrelid is
6807                  * redundant but useful because that column is indexed while conindid
6808                  * is not.
6809                  */
6810                 resetPQExpBuffer(query);
6811                 if (fout->remoteVersion >= 110000)
6812                 {
6813                         appendPQExpBuffer(query,
6814                                                           "SELECT t.tableoid, t.oid, "
6815                                                           "t.relname AS indexname, "
6816                                                           "inh.inhparent AS parentidx, "
6817                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6818                                                           "i.indnkeyatts AS indnkeyatts, "
6819                                                           "i.indnatts AS indnatts, "
6820                                                           "i.indkey, i.indisclustered, "
6821                                                           "i.indisreplident, "
6822                                                           "c.contype, c.conname, "
6823                                                           "c.condeferrable, c.condeferred, "
6824                                                           "c.tableoid AS contableoid, "
6825                                                           "c.oid AS conoid, "
6826                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6827                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6828                                                           "t.reloptions AS indreloptions "
6829                                                           "FROM pg_catalog.pg_index i "
6830                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6831                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6832                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6833                                                           "ON (i.indrelid = c.conrelid AND "
6834                                                           "i.indexrelid = c.conindid AND "
6835                                                           "c.contype IN ('p','u','x')) "
6836                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6837                                                           "ON (inh.inhrelid = indexrelid) "
6838                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6839                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6840                                                           "AND i.indisready "
6841                                                           "ORDER BY indexname",
6842                                                           tbinfo->dobj.catId.oid);
6843                 }
6844                 else if (fout->remoteVersion >= 90400)
6845                 {
6846                         /*
6847                          * the test on indisready is necessary in 9.2, and harmless in
6848                          * earlier/later versions
6849                          */
6850                         appendPQExpBuffer(query,
6851                                                           "SELECT t.tableoid, t.oid, "
6852                                                           "t.relname AS indexname, "
6853                                                           "0 AS parentidx, "
6854                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6855                                                           "i.indnatts AS indnkeyatts, "
6856                                                           "i.indnatts AS indnatts, "
6857                                                           "i.indkey, i.indisclustered, "
6858                                                           "i.indisreplident, "
6859                                                           "c.contype, c.conname, "
6860                                                           "c.condeferrable, c.condeferred, "
6861                                                           "c.tableoid AS contableoid, "
6862                                                           "c.oid AS conoid, "
6863                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6864                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6865                                                           "t.reloptions AS indreloptions "
6866                                                           "FROM pg_catalog.pg_index i "
6867                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6868                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6869                                                           "ON (i.indrelid = c.conrelid AND "
6870                                                           "i.indexrelid = c.conindid AND "
6871                                                           "c.contype IN ('p','u','x')) "
6872                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6873                                                           "AND i.indisvalid AND i.indisready "
6874                                                           "ORDER BY indexname",
6875                                                           tbinfo->dobj.catId.oid);
6876                 }
6877                 else if (fout->remoteVersion >= 90000)
6878                 {
6879                         /*
6880                          * the test on indisready is necessary in 9.2, and harmless in
6881                          * earlier/later versions
6882                          */
6883                         appendPQExpBuffer(query,
6884                                                           "SELECT t.tableoid, t.oid, "
6885                                                           "t.relname AS indexname, "
6886                                                           "0 AS parentidx, "
6887                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6888                                                           "i.indnatts AS indnkeyatts, "
6889                                                           "i.indnatts AS indnatts, "
6890                                                           "i.indkey, i.indisclustered, "
6891                                                           "false AS indisreplident, "
6892                                                           "c.contype, c.conname, "
6893                                                           "c.condeferrable, c.condeferred, "
6894                                                           "c.tableoid AS contableoid, "
6895                                                           "c.oid AS conoid, "
6896                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6897                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6898                                                           "t.reloptions AS indreloptions "
6899                                                           "FROM pg_catalog.pg_index i "
6900                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6901                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6902                                                           "ON (i.indrelid = c.conrelid AND "
6903                                                           "i.indexrelid = c.conindid AND "
6904                                                           "c.contype IN ('p','u','x')) "
6905                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6906                                                           "AND i.indisvalid AND i.indisready "
6907                                                           "ORDER BY indexname",
6908                                                           tbinfo->dobj.catId.oid);
6909                 }
6910                 else if (fout->remoteVersion >= 80200)
6911                 {
6912                         appendPQExpBuffer(query,
6913                                                           "SELECT t.tableoid, t.oid, "
6914                                                           "t.relname AS indexname, "
6915                                                           "0 AS parentidx, "
6916                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6917                                                           "i.indnatts AS indnkeyatts, "
6918                                                           "i.indnatts AS indnatts, "
6919                                                           "i.indkey, i.indisclustered, "
6920                                                           "false AS indisreplident, "
6921                                                           "c.contype, c.conname, "
6922                                                           "c.condeferrable, c.condeferred, "
6923                                                           "c.tableoid AS contableoid, "
6924                                                           "c.oid AS conoid, "
6925                                                           "null AS condef, "
6926                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6927                                                           "t.reloptions AS indreloptions "
6928                                                           "FROM pg_catalog.pg_index i "
6929                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6930                                                           "LEFT JOIN pg_catalog.pg_depend d "
6931                                                           "ON (d.classid = t.tableoid "
6932                                                           "AND d.objid = t.oid "
6933                                                           "AND d.deptype = 'i') "
6934                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6935                                                           "ON (d.refclassid = c.tableoid "
6936                                                           "AND d.refobjid = c.oid) "
6937                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6938                                                           "AND i.indisvalid "
6939                                                           "ORDER BY indexname",
6940                                                           tbinfo->dobj.catId.oid);
6941                 }
6942                 else
6943                 {
6944                         appendPQExpBuffer(query,
6945                                                           "SELECT t.tableoid, t.oid, "
6946                                                           "t.relname AS indexname, "
6947                                                           "0 AS parentidx, "
6948                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6949                                                           "t.relnatts AS indnkeyatts, "
6950                                                           "t.relnatts AS indnatts, "
6951                                                           "i.indkey, i.indisclustered, "
6952                                                           "false AS indisreplident, "
6953                                                           "c.contype, c.conname, "
6954                                                           "c.condeferrable, c.condeferred, "
6955                                                           "c.tableoid AS contableoid, "
6956                                                           "c.oid AS conoid, "
6957                                                           "null AS condef, "
6958                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6959                                                           "null AS indreloptions "
6960                                                           "FROM pg_catalog.pg_index i "
6961                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6962                                                           "LEFT JOIN pg_catalog.pg_depend d "
6963                                                           "ON (d.classid = t.tableoid "
6964                                                           "AND d.objid = t.oid "
6965                                                           "AND d.deptype = 'i') "
6966                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6967                                                           "ON (d.refclassid = c.tableoid "
6968                                                           "AND d.refobjid = c.oid) "
6969                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6970                                                           "ORDER BY indexname",
6971                                                           tbinfo->dobj.catId.oid);
6972                 }
6973
6974                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6975
6976                 ntups = PQntuples(res);
6977
6978                 i_tableoid = PQfnumber(res, "tableoid");
6979                 i_oid = PQfnumber(res, "oid");
6980                 i_indexname = PQfnumber(res, "indexname");
6981                 i_parentidx = PQfnumber(res, "parentidx");
6982                 i_indexdef = PQfnumber(res, "indexdef");
6983                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
6984                 i_indnatts = PQfnumber(res, "indnatts");
6985                 i_indkey = PQfnumber(res, "indkey");
6986                 i_indisclustered = PQfnumber(res, "indisclustered");
6987                 i_indisreplident = PQfnumber(res, "indisreplident");
6988                 i_contype = PQfnumber(res, "contype");
6989                 i_conname = PQfnumber(res, "conname");
6990                 i_condeferrable = PQfnumber(res, "condeferrable");
6991                 i_condeferred = PQfnumber(res, "condeferred");
6992                 i_contableoid = PQfnumber(res, "contableoid");
6993                 i_conoid = PQfnumber(res, "conoid");
6994                 i_condef = PQfnumber(res, "condef");
6995                 i_tablespace = PQfnumber(res, "tablespace");
6996                 i_indreloptions = PQfnumber(res, "indreloptions");
6997
6998                 tbinfo->indexes = indxinfo =
6999                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7000                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7001                 tbinfo->numIndexes = ntups;
7002
7003                 for (j = 0; j < ntups; j++)
7004                 {
7005                         char            contype;
7006
7007                         indxinfo[j].dobj.objType = DO_INDEX;
7008                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7009                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7010                         AssignDumpId(&indxinfo[j].dobj);
7011                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7012                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7013                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7014                         indxinfo[j].indextable = tbinfo;
7015                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7016                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7017                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7018                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7019                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7020                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7021                         parseOidArray(PQgetvalue(res, j, i_indkey),
7022                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
7023                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7024                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7025                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7026                         contype = *(PQgetvalue(res, j, i_contype));
7027
7028                         if (contype == 'p' || contype == 'u' || contype == 'x')
7029                         {
7030                                 /*
7031                                  * If we found a constraint matching the index, create an
7032                                  * entry for it.
7033                                  */
7034                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7035                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7036                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7037                                 AssignDumpId(&constrinfo[j].dobj);
7038                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7039                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7040                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7041                                 constrinfo[j].contable = tbinfo;
7042                                 constrinfo[j].condomain = NULL;
7043                                 constrinfo[j].contype = contype;
7044                                 if (contype == 'x')
7045                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7046                                 else
7047                                         constrinfo[j].condef = NULL;
7048                                 constrinfo[j].confrelid = InvalidOid;
7049                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7050                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7051                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7052                                 constrinfo[j].conislocal = true;
7053                                 constrinfo[j].separate = true;
7054
7055                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7056                         }
7057                         else
7058                         {
7059                                 /* Plain secondary index */
7060                                 indxinfo[j].indexconstraint = 0;
7061                         }
7062                 }
7063
7064                 PQclear(res);
7065         }
7066
7067         destroyPQExpBuffer(query);
7068 }
7069
7070 /*
7071  * getExtendedStatistics
7072  *        get information about extended-statistics objects.
7073  *
7074  * Note: extended statistics data is not returned directly to the caller, but
7075  * it does get entered into the DumpableObject tables.
7076  */
7077 void
7078 getExtendedStatistics(Archive *fout)
7079 {
7080         PQExpBuffer query;
7081         PGresult   *res;
7082         StatsExtInfo *statsextinfo;
7083         int                     ntups;
7084         int                     i_tableoid;
7085         int                     i_oid;
7086         int                     i_stxname;
7087         int                     i_stxnamespace;
7088         int                     i_rolname;
7089         int                     i;
7090
7091         /* Extended statistics were new in v10 */
7092         if (fout->remoteVersion < 100000)
7093                 return;
7094
7095         query = createPQExpBuffer();
7096
7097         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7098                                           "stxnamespace, (%s stxowner) AS rolname "
7099                                           "FROM pg_catalog.pg_statistic_ext",
7100                                           username_subquery);
7101
7102         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7103
7104         ntups = PQntuples(res);
7105
7106         i_tableoid = PQfnumber(res, "tableoid");
7107         i_oid = PQfnumber(res, "oid");
7108         i_stxname = PQfnumber(res, "stxname");
7109         i_stxnamespace = PQfnumber(res, "stxnamespace");
7110         i_rolname = PQfnumber(res, "rolname");
7111
7112         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7113
7114         for (i = 0; i < ntups; i++)
7115         {
7116                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7117                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7118                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7119                 AssignDumpId(&statsextinfo[i].dobj);
7120                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7121                 statsextinfo[i].dobj.namespace =
7122                         findNamespace(fout,
7123                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7124                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7125
7126                 /* Decide whether we want to dump it */
7127                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7128
7129                 /* Stats objects do not currently have ACLs. */
7130                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7131         }
7132
7133         PQclear(res);
7134         destroyPQExpBuffer(query);
7135 }
7136
7137 /*
7138  * getConstraints
7139  *
7140  * Get info about constraints on dumpable tables.
7141  *
7142  * Currently handles foreign keys only.
7143  * Unique and primary key constraints are handled with indexes,
7144  * while check constraints are processed in getTableAttrs().
7145  */
7146 void
7147 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7148 {
7149         int                     i,
7150                                 j;
7151         ConstraintInfo *constrinfo;
7152         PQExpBuffer query;
7153         PGresult   *res;
7154         int                     i_contableoid,
7155                                 i_conoid,
7156                                 i_conname,
7157                                 i_confrelid,
7158                                 i_condef;
7159         int                     ntups;
7160
7161         query = createPQExpBuffer();
7162
7163         for (i = 0; i < numTables; i++)
7164         {
7165                 TableInfo  *tbinfo = &tblinfo[i];
7166
7167                 /*
7168                  * For partitioned tables, foreign keys have no triggers so they must
7169                  * be included anyway in case some foreign keys are defined.
7170                  */
7171                 if ((!tbinfo->hastriggers &&
7172                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7173                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7174                         continue;
7175
7176                 if (g_verbose)
7177                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7178                                           tbinfo->dobj.namespace->dobj.name,
7179                                           tbinfo->dobj.name);
7180
7181                 resetPQExpBuffer(query);
7182                 if (fout->remoteVersion >= 110000)
7183                         appendPQExpBuffer(query,
7184                                                           "SELECT tableoid, oid, conname, confrelid, "
7185                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7186                                                           "FROM pg_catalog.pg_constraint "
7187                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7188                                                           "AND conparentid = 0 "
7189                                                           "AND contype = 'f'",
7190                                                           tbinfo->dobj.catId.oid);
7191                 else
7192                         appendPQExpBuffer(query,
7193                                                           "SELECT tableoid, oid, conname, confrelid, "
7194                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7195                                                           "FROM pg_catalog.pg_constraint "
7196                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7197                                                           "AND contype = 'f'",
7198                                                           tbinfo->dobj.catId.oid);
7199                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7200
7201                 ntups = PQntuples(res);
7202
7203                 i_contableoid = PQfnumber(res, "tableoid");
7204                 i_conoid = PQfnumber(res, "oid");
7205                 i_conname = PQfnumber(res, "conname");
7206                 i_confrelid = PQfnumber(res, "confrelid");
7207                 i_condef = PQfnumber(res, "condef");
7208
7209                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7210
7211                 for (j = 0; j < ntups; j++)
7212                 {
7213                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7214                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7215                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7216                         AssignDumpId(&constrinfo[j].dobj);
7217                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7218                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7219                         constrinfo[j].contable = tbinfo;
7220                         constrinfo[j].condomain = NULL;
7221                         constrinfo[j].contype = 'f';
7222                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7223                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7224                         constrinfo[j].conindex = 0;
7225                         constrinfo[j].condeferrable = false;
7226                         constrinfo[j].condeferred = false;
7227                         constrinfo[j].conislocal = true;
7228                         constrinfo[j].separate = true;
7229                 }
7230
7231                 PQclear(res);
7232         }
7233
7234         destroyPQExpBuffer(query);
7235 }
7236
7237 /*
7238  * getDomainConstraints
7239  *
7240  * Get info about constraints on a domain.
7241  */
7242 static void
7243 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7244 {
7245         int                     i;
7246         ConstraintInfo *constrinfo;
7247         PQExpBuffer query;
7248         PGresult   *res;
7249         int                     i_tableoid,
7250                                 i_oid,
7251                                 i_conname,
7252                                 i_consrc;
7253         int                     ntups;
7254
7255         query = createPQExpBuffer();
7256
7257         if (fout->remoteVersion >= 90100)
7258                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7259                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7260                                                   "convalidated "
7261                                                   "FROM pg_catalog.pg_constraint "
7262                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7263                                                   "ORDER BY conname",
7264                                                   tyinfo->dobj.catId.oid);
7265
7266         else
7267                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7268                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7269                                                   "true as convalidated "
7270                                                   "FROM pg_catalog.pg_constraint "
7271                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7272                                                   "ORDER BY conname",
7273                                                   tyinfo->dobj.catId.oid);
7274
7275         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7276
7277         ntups = PQntuples(res);
7278
7279         i_tableoid = PQfnumber(res, "tableoid");
7280         i_oid = PQfnumber(res, "oid");
7281         i_conname = PQfnumber(res, "conname");
7282         i_consrc = PQfnumber(res, "consrc");
7283
7284         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7285
7286         tyinfo->nDomChecks = ntups;
7287         tyinfo->domChecks = constrinfo;
7288
7289         for (i = 0; i < ntups; i++)
7290         {
7291                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7292
7293                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7294                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7295                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7296                 AssignDumpId(&constrinfo[i].dobj);
7297                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7298                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7299                 constrinfo[i].contable = NULL;
7300                 constrinfo[i].condomain = tyinfo;
7301                 constrinfo[i].contype = 'c';
7302                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7303                 constrinfo[i].confrelid = InvalidOid;
7304                 constrinfo[i].conindex = 0;
7305                 constrinfo[i].condeferrable = false;
7306                 constrinfo[i].condeferred = false;
7307                 constrinfo[i].conislocal = true;
7308
7309                 constrinfo[i].separate = !validated;
7310
7311                 /*
7312                  * Make the domain depend on the constraint, ensuring it won't be
7313                  * output till any constraint dependencies are OK.  If the constraint
7314                  * has not been validated, it's going to be dumped after the domain
7315                  * anyway, so this doesn't matter.
7316                  */
7317                 if (validated)
7318                         addObjectDependency(&tyinfo->dobj,
7319                                                                 constrinfo[i].dobj.dumpId);
7320         }
7321
7322         PQclear(res);
7323
7324         destroyPQExpBuffer(query);
7325 }
7326
7327 /*
7328  * getRules
7329  *        get basic information about every rule in the system
7330  *
7331  * numRules is set to the number of rules read in
7332  */
7333 RuleInfo *
7334 getRules(Archive *fout, int *numRules)
7335 {
7336         PGresult   *res;
7337         int                     ntups;
7338         int                     i;
7339         PQExpBuffer query = createPQExpBuffer();
7340         RuleInfo   *ruleinfo;
7341         int                     i_tableoid;
7342         int                     i_oid;
7343         int                     i_rulename;
7344         int                     i_ruletable;
7345         int                     i_ev_type;
7346         int                     i_is_instead;
7347         int                     i_ev_enabled;
7348
7349         if (fout->remoteVersion >= 80300)
7350         {
7351                 appendPQExpBufferStr(query, "SELECT "
7352                                                          "tableoid, oid, rulename, "
7353                                                          "ev_class AS ruletable, ev_type, is_instead, "
7354                                                          "ev_enabled "
7355                                                          "FROM pg_rewrite "
7356                                                          "ORDER BY oid");
7357         }
7358         else
7359         {
7360                 appendPQExpBufferStr(query, "SELECT "
7361                                                          "tableoid, oid, rulename, "
7362                                                          "ev_class AS ruletable, ev_type, is_instead, "
7363                                                          "'O'::char AS ev_enabled "
7364                                                          "FROM pg_rewrite "
7365                                                          "ORDER BY oid");
7366         }
7367
7368         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7369
7370         ntups = PQntuples(res);
7371
7372         *numRules = ntups;
7373
7374         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7375
7376         i_tableoid = PQfnumber(res, "tableoid");
7377         i_oid = PQfnumber(res, "oid");
7378         i_rulename = PQfnumber(res, "rulename");
7379         i_ruletable = PQfnumber(res, "ruletable");
7380         i_ev_type = PQfnumber(res, "ev_type");
7381         i_is_instead = PQfnumber(res, "is_instead");
7382         i_ev_enabled = PQfnumber(res, "ev_enabled");
7383
7384         for (i = 0; i < ntups; i++)
7385         {
7386                 Oid                     ruletableoid;
7387
7388                 ruleinfo[i].dobj.objType = DO_RULE;
7389                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7390                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7391                 AssignDumpId(&ruleinfo[i].dobj);
7392                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7393                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7394                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7395                 if (ruleinfo[i].ruletable == NULL)
7396                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7397                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7398                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7399                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7400                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7401                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7402                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7403                 if (ruleinfo[i].ruletable)
7404                 {
7405                         /*
7406                          * If the table is a view or materialized view, force its ON
7407                          * SELECT rule to be sorted before the view itself --- this
7408                          * ensures that any dependencies for the rule affect the table's
7409                          * positioning. Other rules are forced to appear after their
7410                          * table.
7411                          */
7412                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7413                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7414                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7415                         {
7416                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7417                                                                         ruleinfo[i].dobj.dumpId);
7418                                 /* We'll merge the rule into CREATE VIEW, if possible */
7419                                 ruleinfo[i].separate = false;
7420                         }
7421                         else
7422                         {
7423                                 addObjectDependency(&ruleinfo[i].dobj,
7424                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7425                                 ruleinfo[i].separate = true;
7426                         }
7427                 }
7428                 else
7429                         ruleinfo[i].separate = true;
7430         }
7431
7432         PQclear(res);
7433
7434         destroyPQExpBuffer(query);
7435
7436         return ruleinfo;
7437 }
7438
7439 /*
7440  * getTriggers
7441  *        get information about every trigger on a dumpable table
7442  *
7443  * Note: trigger data is not returned directly to the caller, but it
7444  * does get entered into the DumpableObject tables.
7445  */
7446 void
7447 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7448 {
7449         int                     i,
7450                                 j;
7451         PQExpBuffer query = createPQExpBuffer();
7452         PGresult   *res;
7453         TriggerInfo *tginfo;
7454         int                     i_tableoid,
7455                                 i_oid,
7456                                 i_tgname,
7457                                 i_tgfname,
7458                                 i_tgtype,
7459                                 i_tgnargs,
7460                                 i_tgargs,
7461                                 i_tgisconstraint,
7462                                 i_tgconstrname,
7463                                 i_tgconstrrelid,
7464                                 i_tgconstrrelname,
7465                                 i_tgenabled,
7466                                 i_tgdeferrable,
7467                                 i_tginitdeferred,
7468                                 i_tgdef;
7469         int                     ntups;
7470
7471         for (i = 0; i < numTables; i++)
7472         {
7473                 TableInfo  *tbinfo = &tblinfo[i];
7474
7475                 if (!tbinfo->hastriggers ||
7476                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7477                         continue;
7478
7479                 if (g_verbose)
7480                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7481                                           tbinfo->dobj.namespace->dobj.name,
7482                                           tbinfo->dobj.name);
7483
7484                 resetPQExpBuffer(query);
7485                 if (fout->remoteVersion >= 90000)
7486                 {
7487                         /*
7488                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7489                          * could result in non-forward-compatible dumps of WHEN clauses
7490                          * due to under-parenthesization.
7491                          */
7492                         appendPQExpBuffer(query,
7493                                                           "SELECT tgname, "
7494                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7495                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7496                                                           "tgenabled, tableoid, oid "
7497                                                           "FROM pg_catalog.pg_trigger t "
7498                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7499                                                           "AND NOT tgisinternal",
7500                                                           tbinfo->dobj.catId.oid);
7501                 }
7502                 else if (fout->remoteVersion >= 80300)
7503                 {
7504                         /*
7505                          * We ignore triggers that are tied to a foreign-key constraint
7506                          */
7507                         appendPQExpBuffer(query,
7508                                                           "SELECT tgname, "
7509                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7510                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7511                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7512                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7513                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7514                                                           "FROM pg_catalog.pg_trigger t "
7515                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7516                                                           "AND tgconstraint = 0",
7517                                                           tbinfo->dobj.catId.oid);
7518                 }
7519                 else
7520                 {
7521                         /*
7522                          * We ignore triggers that are tied to a foreign-key constraint,
7523                          * but in these versions we have to grovel through pg_constraint
7524                          * to find out
7525                          */
7526                         appendPQExpBuffer(query,
7527                                                           "SELECT tgname, "
7528                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7529                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7530                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7531                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7532                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7533                                                           "FROM pg_catalog.pg_trigger t "
7534                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7535                                                           "AND (NOT tgisconstraint "
7536                                                           " OR NOT EXISTS"
7537                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7538                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7539                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7540                                                           tbinfo->dobj.catId.oid);
7541                 }
7542
7543                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7544
7545                 ntups = PQntuples(res);
7546
7547                 i_tableoid = PQfnumber(res, "tableoid");
7548                 i_oid = PQfnumber(res, "oid");
7549                 i_tgname = PQfnumber(res, "tgname");
7550                 i_tgfname = PQfnumber(res, "tgfname");
7551                 i_tgtype = PQfnumber(res, "tgtype");
7552                 i_tgnargs = PQfnumber(res, "tgnargs");
7553                 i_tgargs = PQfnumber(res, "tgargs");
7554                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7555                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7556                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7557                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7558                 i_tgenabled = PQfnumber(res, "tgenabled");
7559                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7560                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7561                 i_tgdef = PQfnumber(res, "tgdef");
7562
7563                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7564
7565                 tbinfo->numTriggers = ntups;
7566                 tbinfo->triggers = tginfo;
7567
7568                 for (j = 0; j < ntups; j++)
7569                 {
7570                         tginfo[j].dobj.objType = DO_TRIGGER;
7571                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7572                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7573                         AssignDumpId(&tginfo[j].dobj);
7574                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7575                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7576                         tginfo[j].tgtable = tbinfo;
7577                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7578                         if (i_tgdef >= 0)
7579                         {
7580                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7581
7582                                 /* remaining fields are not valid if we have tgdef */
7583                                 tginfo[j].tgfname = NULL;
7584                                 tginfo[j].tgtype = 0;
7585                                 tginfo[j].tgnargs = 0;
7586                                 tginfo[j].tgargs = NULL;
7587                                 tginfo[j].tgisconstraint = false;
7588                                 tginfo[j].tgdeferrable = false;
7589                                 tginfo[j].tginitdeferred = false;
7590                                 tginfo[j].tgconstrname = NULL;
7591                                 tginfo[j].tgconstrrelid = InvalidOid;
7592                                 tginfo[j].tgconstrrelname = NULL;
7593                         }
7594                         else
7595                         {
7596                                 tginfo[j].tgdef = NULL;
7597
7598                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7599                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7600                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7601                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7602                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7603                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7604                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7605
7606                                 if (tginfo[j].tgisconstraint)
7607                                 {
7608                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7609                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7610                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7611                                         {
7612                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7613                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7614                                                                                   tginfo[j].dobj.name,
7615                                                                                   tbinfo->dobj.name,
7616                                                                                   tginfo[j].tgconstrrelid);
7617                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7618                                         }
7619                                         else
7620                                                 tginfo[j].tgconstrrelname = NULL;
7621                                 }
7622                                 else
7623                                 {
7624                                         tginfo[j].tgconstrname = NULL;
7625                                         tginfo[j].tgconstrrelid = InvalidOid;
7626                                         tginfo[j].tgconstrrelname = NULL;
7627                                 }
7628                         }
7629                 }
7630
7631                 PQclear(res);
7632         }
7633
7634         destroyPQExpBuffer(query);
7635 }
7636
7637 /*
7638  * getEventTriggers
7639  *        get information about event triggers
7640  */
7641 EventTriggerInfo *
7642 getEventTriggers(Archive *fout, int *numEventTriggers)
7643 {
7644         int                     i;
7645         PQExpBuffer query;
7646         PGresult   *res;
7647         EventTriggerInfo *evtinfo;
7648         int                     i_tableoid,
7649                                 i_oid,
7650                                 i_evtname,
7651                                 i_evtevent,
7652                                 i_evtowner,
7653                                 i_evttags,
7654                                 i_evtfname,
7655                                 i_evtenabled;
7656         int                     ntups;
7657
7658         /* Before 9.3, there are no event triggers */
7659         if (fout->remoteVersion < 90300)
7660         {
7661                 *numEventTriggers = 0;
7662                 return NULL;
7663         }
7664
7665         query = createPQExpBuffer();
7666
7667         appendPQExpBuffer(query,
7668                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7669                                           "evtevent, (%s evtowner) AS evtowner, "
7670                                           "array_to_string(array("
7671                                           "select quote_literal(x) "
7672                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7673                                           "e.evtfoid::regproc as evtfname "
7674                                           "FROM pg_event_trigger e "
7675                                           "ORDER BY e.oid",
7676                                           username_subquery);
7677
7678         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7679
7680         ntups = PQntuples(res);
7681
7682         *numEventTriggers = ntups;
7683
7684         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7685
7686         i_tableoid = PQfnumber(res, "tableoid");
7687         i_oid = PQfnumber(res, "oid");
7688         i_evtname = PQfnumber(res, "evtname");
7689         i_evtevent = PQfnumber(res, "evtevent");
7690         i_evtowner = PQfnumber(res, "evtowner");
7691         i_evttags = PQfnumber(res, "evttags");
7692         i_evtfname = PQfnumber(res, "evtfname");
7693         i_evtenabled = PQfnumber(res, "evtenabled");
7694
7695         for (i = 0; i < ntups; i++)
7696         {
7697                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7698                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7699                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7700                 AssignDumpId(&evtinfo[i].dobj);
7701                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7702                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7703                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7704                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7705                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7706                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7707                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7708
7709                 /* Decide whether we want to dump it */
7710                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7711
7712                 /* Event Triggers do not currently have ACLs. */
7713                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7714         }
7715
7716         PQclear(res);
7717
7718         destroyPQExpBuffer(query);
7719
7720         return evtinfo;
7721 }
7722
7723 /*
7724  * getProcLangs
7725  *        get basic information about every procedural language in the system
7726  *
7727  * numProcLangs is set to the number of langs read in
7728  *
7729  * NB: this must run after getFuncs() because we assume we can do
7730  * findFuncByOid().
7731  */
7732 ProcLangInfo *
7733 getProcLangs(Archive *fout, int *numProcLangs)
7734 {
7735         DumpOptions *dopt = fout->dopt;
7736         PGresult   *res;
7737         int                     ntups;
7738         int                     i;
7739         PQExpBuffer query = createPQExpBuffer();
7740         ProcLangInfo *planginfo;
7741         int                     i_tableoid;
7742         int                     i_oid;
7743         int                     i_lanname;
7744         int                     i_lanpltrusted;
7745         int                     i_lanplcallfoid;
7746         int                     i_laninline;
7747         int                     i_lanvalidator;
7748         int                     i_lanacl;
7749         int                     i_rlanacl;
7750         int                     i_initlanacl;
7751         int                     i_initrlanacl;
7752         int                     i_lanowner;
7753
7754         if (fout->remoteVersion >= 90600)
7755         {
7756                 PQExpBuffer acl_subquery = createPQExpBuffer();
7757                 PQExpBuffer racl_subquery = createPQExpBuffer();
7758                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7759                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7760
7761                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7762                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7763                                                 dopt->binary_upgrade);
7764
7765                 /* pg_language has a laninline column */
7766                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7767                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7768                                                   "l.laninline, l.lanvalidator, "
7769                                                   "%s AS lanacl, "
7770                                                   "%s AS rlanacl, "
7771                                                   "%s AS initlanacl, "
7772                                                   "%s AS initrlanacl, "
7773                                                   "(%s l.lanowner) AS lanowner "
7774                                                   "FROM pg_language l "
7775                                                   "LEFT JOIN pg_init_privs pip ON "
7776                                                   "(l.oid = pip.objoid "
7777                                                   "AND pip.classoid = 'pg_language'::regclass "
7778                                                   "AND pip.objsubid = 0) "
7779                                                   "WHERE l.lanispl "
7780                                                   "ORDER BY l.oid",
7781                                                   acl_subquery->data,
7782                                                   racl_subquery->data,
7783                                                   initacl_subquery->data,
7784                                                   initracl_subquery->data,
7785                                                   username_subquery);
7786
7787                 destroyPQExpBuffer(acl_subquery);
7788                 destroyPQExpBuffer(racl_subquery);
7789                 destroyPQExpBuffer(initacl_subquery);
7790                 destroyPQExpBuffer(initracl_subquery);
7791         }
7792         else if (fout->remoteVersion >= 90000)
7793         {
7794                 /* pg_language has a laninline column */
7795                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7796                                                   "lanname, lanpltrusted, lanplcallfoid, "
7797                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7798                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7799                                                   "(%s lanowner) AS lanowner "
7800                                                   "FROM pg_language "
7801                                                   "WHERE lanispl "
7802                                                   "ORDER BY oid",
7803                                                   username_subquery);
7804         }
7805         else if (fout->remoteVersion >= 80300)
7806         {
7807                 /* pg_language has a lanowner column */
7808                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7809                                                   "lanname, lanpltrusted, lanplcallfoid, "
7810                                                   "0 AS laninline, lanvalidator, lanacl, "
7811                                                   "NULL AS rlanacl, "
7812                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7813                                                   "(%s lanowner) AS lanowner "
7814                                                   "FROM pg_language "
7815                                                   "WHERE lanispl "
7816                                                   "ORDER BY oid",
7817                                                   username_subquery);
7818         }
7819         else if (fout->remoteVersion >= 80100)
7820         {
7821                 /* Languages are owned by the bootstrap superuser, OID 10 */
7822                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7823                                                   "lanname, lanpltrusted, lanplcallfoid, "
7824                                                   "0 AS laninline, lanvalidator, lanacl, "
7825                                                   "NULL AS rlanacl, "
7826                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7827                                                   "(%s '10') AS lanowner "
7828                                                   "FROM pg_language "
7829                                                   "WHERE lanispl "
7830                                                   "ORDER BY oid",
7831                                                   username_subquery);
7832         }
7833         else
7834         {
7835                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7836                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7837                                                   "lanname, lanpltrusted, lanplcallfoid, "
7838                                                   "0 AS laninline, lanvalidator, lanacl, "
7839                                                   "NULL AS rlanacl, "
7840                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7841                                                   "(%s '1') AS lanowner "
7842                                                   "FROM pg_language "
7843                                                   "WHERE lanispl "
7844                                                   "ORDER BY oid",
7845                                                   username_subquery);
7846         }
7847
7848         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7849
7850         ntups = PQntuples(res);
7851
7852         *numProcLangs = ntups;
7853
7854         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7855
7856         i_tableoid = PQfnumber(res, "tableoid");
7857         i_oid = PQfnumber(res, "oid");
7858         i_lanname = PQfnumber(res, "lanname");
7859         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7860         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7861         i_laninline = PQfnumber(res, "laninline");
7862         i_lanvalidator = PQfnumber(res, "lanvalidator");
7863         i_lanacl = PQfnumber(res, "lanacl");
7864         i_rlanacl = PQfnumber(res, "rlanacl");
7865         i_initlanacl = PQfnumber(res, "initlanacl");
7866         i_initrlanacl = PQfnumber(res, "initrlanacl");
7867         i_lanowner = PQfnumber(res, "lanowner");
7868
7869         for (i = 0; i < ntups; i++)
7870         {
7871                 planginfo[i].dobj.objType = DO_PROCLANG;
7872                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7873                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7874                 AssignDumpId(&planginfo[i].dobj);
7875
7876                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7877                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7878                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7879                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7880                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7881                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7882                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7883                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7884                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7885                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7886
7887                 /* Decide whether we want to dump it */
7888                 selectDumpableProcLang(&(planginfo[i]), fout);
7889
7890                 /* Do not try to dump ACL if no ACL exists. */
7891                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7892                         PQgetisnull(res, i, i_initlanacl) &&
7893                         PQgetisnull(res, i, i_initrlanacl))
7894                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7895         }
7896
7897         PQclear(res);
7898
7899         destroyPQExpBuffer(query);
7900
7901         return planginfo;
7902 }
7903
7904 /*
7905  * getCasts
7906  *        get basic information about every cast in the system
7907  *
7908  * numCasts is set to the number of casts read in
7909  */
7910 CastInfo *
7911 getCasts(Archive *fout, int *numCasts)
7912 {
7913         PGresult   *res;
7914         int                     ntups;
7915         int                     i;
7916         PQExpBuffer query = createPQExpBuffer();
7917         CastInfo   *castinfo;
7918         int                     i_tableoid;
7919         int                     i_oid;
7920         int                     i_castsource;
7921         int                     i_casttarget;
7922         int                     i_castfunc;
7923         int                     i_castcontext;
7924         int                     i_castmethod;
7925
7926         if (fout->remoteVersion >= 80400)
7927         {
7928                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7929                                                          "castsource, casttarget, castfunc, castcontext, "
7930                                                          "castmethod "
7931                                                          "FROM pg_cast ORDER BY 3,4");
7932         }
7933         else
7934         {
7935                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7936                                                          "castsource, casttarget, castfunc, castcontext, "
7937                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7938                                                          "FROM pg_cast ORDER BY 3,4");
7939         }
7940
7941         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7942
7943         ntups = PQntuples(res);
7944
7945         *numCasts = ntups;
7946
7947         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7948
7949         i_tableoid = PQfnumber(res, "tableoid");
7950         i_oid = PQfnumber(res, "oid");
7951         i_castsource = PQfnumber(res, "castsource");
7952         i_casttarget = PQfnumber(res, "casttarget");
7953         i_castfunc = PQfnumber(res, "castfunc");
7954         i_castcontext = PQfnumber(res, "castcontext");
7955         i_castmethod = PQfnumber(res, "castmethod");
7956
7957         for (i = 0; i < ntups; i++)
7958         {
7959                 PQExpBufferData namebuf;
7960                 TypeInfo   *sTypeInfo;
7961                 TypeInfo   *tTypeInfo;
7962
7963                 castinfo[i].dobj.objType = DO_CAST;
7964                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7965                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7966                 AssignDumpId(&castinfo[i].dobj);
7967                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7968                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7969                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7970                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7971                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7972
7973                 /*
7974                  * Try to name cast as concatenation of typnames.  This is only used
7975                  * for purposes of sorting.  If we fail to find either type, the name
7976                  * will be an empty string.
7977                  */
7978                 initPQExpBuffer(&namebuf);
7979                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
7980                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7981                 if (sTypeInfo && tTypeInfo)
7982                         appendPQExpBuffer(&namebuf, "%s %s",
7983                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7984                 castinfo[i].dobj.name = namebuf.data;
7985
7986                 /* Decide whether we want to dump it */
7987                 selectDumpableCast(&(castinfo[i]), fout);
7988
7989                 /* Casts do not currently have ACLs. */
7990                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7991         }
7992
7993         PQclear(res);
7994
7995         destroyPQExpBuffer(query);
7996
7997         return castinfo;
7998 }
7999
8000 static char *
8001 get_language_name(Archive *fout, Oid langid)
8002 {
8003         PQExpBuffer query;
8004         PGresult   *res;
8005         char       *lanname;
8006
8007         query = createPQExpBuffer();
8008         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8009         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8010         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8011         destroyPQExpBuffer(query);
8012         PQclear(res);
8013
8014         return lanname;
8015 }
8016
8017 /*
8018  * getTransforms
8019  *        get basic information about every transform in the system
8020  *
8021  * numTransforms is set to the number of transforms read in
8022  */
8023 TransformInfo *
8024 getTransforms(Archive *fout, int *numTransforms)
8025 {
8026         PGresult   *res;
8027         int                     ntups;
8028         int                     i;
8029         PQExpBuffer query;
8030         TransformInfo *transforminfo;
8031         int                     i_tableoid;
8032         int                     i_oid;
8033         int                     i_trftype;
8034         int                     i_trflang;
8035         int                     i_trffromsql;
8036         int                     i_trftosql;
8037
8038         /* Transforms didn't exist pre-9.5 */
8039         if (fout->remoteVersion < 90500)
8040         {
8041                 *numTransforms = 0;
8042                 return NULL;
8043         }
8044
8045         query = createPQExpBuffer();
8046
8047         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8048                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8049                                           "FROM pg_transform "
8050                                           "ORDER BY 3,4");
8051
8052         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8053
8054         ntups = PQntuples(res);
8055
8056         *numTransforms = ntups;
8057
8058         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8059
8060         i_tableoid = PQfnumber(res, "tableoid");
8061         i_oid = PQfnumber(res, "oid");
8062         i_trftype = PQfnumber(res, "trftype");
8063         i_trflang = PQfnumber(res, "trflang");
8064         i_trffromsql = PQfnumber(res, "trffromsql");
8065         i_trftosql = PQfnumber(res, "trftosql");
8066
8067         for (i = 0; i < ntups; i++)
8068         {
8069                 PQExpBufferData namebuf;
8070                 TypeInfo   *typeInfo;
8071                 char       *lanname;
8072
8073                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8074                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8075                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8076                 AssignDumpId(&transforminfo[i].dobj);
8077                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8078                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8079                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8080                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8081
8082                 /*
8083                  * Try to name transform as concatenation of type and language name.
8084                  * This is only used for purposes of sorting.  If we fail to find
8085                  * either, the name will be an empty string.
8086                  */
8087                 initPQExpBuffer(&namebuf);
8088                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8089                 lanname = get_language_name(fout, transforminfo[i].trflang);
8090                 if (typeInfo && lanname)
8091                         appendPQExpBuffer(&namebuf, "%s %s",
8092                                                           typeInfo->dobj.name, lanname);
8093                 transforminfo[i].dobj.name = namebuf.data;
8094                 free(lanname);
8095
8096                 /* Decide whether we want to dump it */
8097                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8098         }
8099
8100         PQclear(res);
8101
8102         destroyPQExpBuffer(query);
8103
8104         return transforminfo;
8105 }
8106
8107 /*
8108  * getTableAttrs -
8109  *        for each interesting table, read info about its attributes
8110  *        (names, types, default values, CHECK constraints, etc)
8111  *
8112  * This is implemented in a very inefficient way right now, looping
8113  * through the tblinfo and doing a join per table to find the attrs and their
8114  * types.  However, because we want type names and so forth to be named
8115  * relative to the schema of each table, we couldn't do it in just one
8116  * query.  (Maybe one query per schema?)
8117  *
8118  *      modifies tblinfo
8119  */
8120 void
8121 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8122 {
8123         DumpOptions *dopt = fout->dopt;
8124         int                     i,
8125                                 j;
8126         PQExpBuffer q = createPQExpBuffer();
8127         int                     i_attnum;
8128         int                     i_attname;
8129         int                     i_atttypname;
8130         int                     i_atttypmod;
8131         int                     i_attstattarget;
8132         int                     i_attstorage;
8133         int                     i_typstorage;
8134         int                     i_attnotnull;
8135         int                     i_atthasdef;
8136         int                     i_attidentity;
8137         int                     i_attisdropped;
8138         int                     i_attlen;
8139         int                     i_attalign;
8140         int                     i_attislocal;
8141         int                     i_attoptions;
8142         int                     i_attcollation;
8143         int                     i_attfdwoptions;
8144         int                     i_attmissingval;
8145         PGresult   *res;
8146         int                     ntups;
8147         bool            hasdefaults;
8148
8149         for (i = 0; i < numTables; i++)
8150         {
8151                 TableInfo  *tbinfo = &tblinfo[i];
8152
8153                 /* Don't bother to collect info for sequences */
8154                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8155                         continue;
8156
8157                 /* Don't bother with uninteresting tables, either */
8158                 if (!tbinfo->interesting)
8159                         continue;
8160
8161                 /* find all the user attributes and their types */
8162
8163                 /*
8164                  * we must read the attribute names in attribute number order! because
8165                  * we will use the attnum to index into the attnames array later.
8166                  */
8167                 if (g_verbose)
8168                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8169                                           tbinfo->dobj.namespace->dobj.name,
8170                                           tbinfo->dobj.name);
8171
8172                 resetPQExpBuffer(q);
8173
8174                 appendPQExpBuffer(q,
8175                                                   "SELECT\n"
8176                                                   "a.attnum,\n"
8177                                                   "a.attname,\n"
8178                                                   "a.atttypmod,\n"
8179                                                   "a.attstattarget,\n"
8180                                                   "a.attstorage,\n"
8181                                                   "t.typstorage,\n"
8182                                                   "a.attnotnull,\n"
8183                                                   "a.atthasdef,\n"
8184                                                   "a.attisdropped,\n"
8185                                                   "a.attlen,\n"
8186                                                   "a.attalign,\n"
8187                                                   "a.attislocal,\n"
8188                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8189
8190                 if (fout->remoteVersion >= 110000)
8191                         appendPQExpBuffer(q,
8192                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8193                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8194                 else
8195                         appendPQExpBuffer(q,
8196                                                           "NULL AS attmissingval,\n");
8197
8198                 if (fout->remoteVersion >= 100000)
8199                         appendPQExpBuffer(q,
8200                                                           "a.attidentity,\n");
8201                 else
8202                         appendPQExpBuffer(q,
8203                                                           "'' AS attidentity,\n");
8204
8205                 if (fout->remoteVersion >= 90200)
8206                         appendPQExpBuffer(q,
8207                                                           "pg_catalog.array_to_string(ARRAY("
8208                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8209                                                           "' ' || pg_catalog.quote_literal(option_value) "
8210                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8211                                                           "ORDER BY option_name"
8212                                                           "), E',\n    ') AS attfdwoptions,\n");
8213                 else
8214                         appendPQExpBuffer(q,
8215                                                           "'' AS attfdwoptions,\n");
8216
8217                 if (fout->remoteVersion >= 90100)
8218                 {
8219                         /*
8220                          * Since we only want to dump COLLATE clauses for attributes whose
8221                          * collation is different from their type's default, we use a CASE
8222                          * here to suppress uninteresting attcollations cheaply.
8223                          */
8224                         appendPQExpBuffer(q,
8225                                                           "CASE WHEN a.attcollation <> t.typcollation "
8226                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8227                 }
8228                 else
8229                         appendPQExpBuffer(q,
8230                                                           "0 AS attcollation,\n");
8231
8232                 if (fout->remoteVersion >= 90000)
8233                         appendPQExpBuffer(q,
8234                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8235                 else
8236                         appendPQExpBuffer(q,
8237                                                           "'' AS attoptions\n");
8238
8239                 /* need left join here to not fail on dropped columns ... */
8240                 appendPQExpBuffer(q,
8241                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8242                                                   "ON a.atttypid = t.oid\n"
8243                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8244                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8245                                                   "ORDER BY a.attnum",
8246                                                   tbinfo->dobj.catId.oid);
8247
8248                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8249
8250                 ntups = PQntuples(res);
8251
8252                 i_attnum = PQfnumber(res, "attnum");
8253                 i_attname = PQfnumber(res, "attname");
8254                 i_atttypname = PQfnumber(res, "atttypname");
8255                 i_atttypmod = PQfnumber(res, "atttypmod");
8256                 i_attstattarget = PQfnumber(res, "attstattarget");
8257                 i_attstorage = PQfnumber(res, "attstorage");
8258                 i_typstorage = PQfnumber(res, "typstorage");
8259                 i_attnotnull = PQfnumber(res, "attnotnull");
8260                 i_atthasdef = PQfnumber(res, "atthasdef");
8261                 i_attidentity = PQfnumber(res, "attidentity");
8262                 i_attisdropped = PQfnumber(res, "attisdropped");
8263                 i_attlen = PQfnumber(res, "attlen");
8264                 i_attalign = PQfnumber(res, "attalign");
8265                 i_attislocal = PQfnumber(res, "attislocal");
8266                 i_attoptions = PQfnumber(res, "attoptions");
8267                 i_attcollation = PQfnumber(res, "attcollation");
8268                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8269                 i_attmissingval = PQfnumber(res, "attmissingval");
8270
8271                 tbinfo->numatts = ntups;
8272                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8273                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8274                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8275                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8276                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8277                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8278                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8279                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8280                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8281                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8282                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8283                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8284                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8285                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8286                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8287                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8288                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8289                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8290                 hasdefaults = false;
8291
8292                 for (j = 0; j < ntups; j++)
8293                 {
8294                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8295                                 exit_horribly(NULL,
8296                                                           "invalid column numbering in table \"%s\"\n",
8297                                                           tbinfo->dobj.name);
8298                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8299                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8300                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8301                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8302                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8303                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8304                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8305                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8306                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8307                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8308                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8309                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8310                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8311                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8312                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8313                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8314                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8315                         tbinfo->attrdefs[j] = NULL; /* fix below */
8316                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8317                                 hasdefaults = true;
8318                         /* these flags will be set in flagInhAttrs() */
8319                         tbinfo->inhNotNull[j] = false;
8320                 }
8321
8322                 PQclear(res);
8323
8324                 /*
8325                  * Get info about column defaults
8326                  */
8327                 if (hasdefaults)
8328                 {
8329                         AttrDefInfo *attrdefs;
8330                         int                     numDefaults;
8331
8332                         if (g_verbose)
8333                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8334                                                   tbinfo->dobj.namespace->dobj.name,
8335                                                   tbinfo->dobj.name);
8336
8337                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8338                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8339                                                           "FROM pg_catalog.pg_attrdef "
8340                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8341                                                           tbinfo->dobj.catId.oid);
8342
8343                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8344
8345                         numDefaults = PQntuples(res);
8346                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8347
8348                         for (j = 0; j < numDefaults; j++)
8349                         {
8350                                 int                     adnum;
8351
8352                                 adnum = atoi(PQgetvalue(res, j, 2));
8353
8354                                 if (adnum <= 0 || adnum > ntups)
8355                                         exit_horribly(NULL,
8356                                                                   "invalid adnum value %d for table \"%s\"\n",
8357                                                                   adnum, tbinfo->dobj.name);
8358
8359                                 /*
8360                                  * dropped columns shouldn't have defaults, but just in case,
8361                                  * ignore 'em
8362                                  */
8363                                 if (tbinfo->attisdropped[adnum - 1])
8364                                         continue;
8365
8366                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8367                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8368                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8369                                 AssignDumpId(&attrdefs[j].dobj);
8370                                 attrdefs[j].adtable = tbinfo;
8371                                 attrdefs[j].adnum = adnum;
8372                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8373
8374                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8375                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8376
8377                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8378
8379                                 /*
8380                                  * Defaults on a VIEW must always be dumped as separate ALTER
8381                                  * TABLE commands.  Defaults on regular tables are dumped as
8382                                  * part of the CREATE TABLE if possible, which it won't be if
8383                                  * the column is not going to be emitted explicitly.
8384                                  */
8385                                 if (tbinfo->relkind == RELKIND_VIEW)
8386                                 {
8387                                         attrdefs[j].separate = true;
8388                                 }
8389                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8390                                 {
8391                                         /* column will be suppressed, print default separately */
8392                                         attrdefs[j].separate = true;
8393                                 }
8394                                 else
8395                                 {
8396                                         attrdefs[j].separate = false;
8397
8398                                         /*
8399                                          * Mark the default as needing to appear before the table,
8400                                          * so that any dependencies it has must be emitted before
8401                                          * the CREATE TABLE.  If this is not possible, we'll
8402                                          * change to "separate" mode while sorting dependencies.
8403                                          */
8404                                         addObjectDependency(&tbinfo->dobj,
8405                                                                                 attrdefs[j].dobj.dumpId);
8406                                 }
8407
8408                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8409                         }
8410                         PQclear(res);
8411                 }
8412
8413                 /*
8414                  * Get info about table CHECK constraints
8415                  */
8416                 if (tbinfo->ncheck > 0)
8417                 {
8418                         ConstraintInfo *constrs;
8419                         int                     numConstrs;
8420
8421                         if (g_verbose)
8422                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8423                                                   tbinfo->dobj.namespace->dobj.name,
8424                                                   tbinfo->dobj.name);
8425
8426                         resetPQExpBuffer(q);
8427                         if (fout->remoteVersion >= 90200)
8428                         {
8429                                 /*
8430                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8431                                  * but it wasn't ever false for check constraints until 9.2).
8432                                  */
8433                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8434                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8435                                                                   "conislocal, convalidated "
8436                                                                   "FROM pg_catalog.pg_constraint "
8437                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8438                                                                   "   AND contype = 'c' "
8439                                                                   "ORDER BY conname",
8440                                                                   tbinfo->dobj.catId.oid);
8441                         }
8442                         else if (fout->remoteVersion >= 80400)
8443                         {
8444                                 /* conislocal is new in 8.4 */
8445                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8446                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8447                                                                   "conislocal, true AS convalidated "
8448                                                                   "FROM pg_catalog.pg_constraint "
8449                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8450                                                                   "   AND contype = 'c' "
8451                                                                   "ORDER BY conname",
8452                                                                   tbinfo->dobj.catId.oid);
8453                         }
8454                         else
8455                         {
8456                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8457                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8458                                                                   "true AS conislocal, true AS convalidated "
8459                                                                   "FROM pg_catalog.pg_constraint "
8460                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8461                                                                   "   AND contype = 'c' "
8462                                                                   "ORDER BY conname",
8463                                                                   tbinfo->dobj.catId.oid);
8464                         }
8465
8466                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8467
8468                         numConstrs = PQntuples(res);
8469                         if (numConstrs != tbinfo->ncheck)
8470                         {
8471                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8472                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8473                                                                                  tbinfo->ncheck),
8474                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8475                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8476                                 exit_nicely(1);
8477                         }
8478
8479                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8480                         tbinfo->checkexprs = constrs;
8481
8482                         for (j = 0; j < numConstrs; j++)
8483                         {
8484                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8485
8486                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8487                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8488                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8489                                 AssignDumpId(&constrs[j].dobj);
8490                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8491                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8492                                 constrs[j].contable = tbinfo;
8493                                 constrs[j].condomain = NULL;
8494                                 constrs[j].contype = 'c';
8495                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8496                                 constrs[j].confrelid = InvalidOid;
8497                                 constrs[j].conindex = 0;
8498                                 constrs[j].condeferrable = false;
8499                                 constrs[j].condeferred = false;
8500                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8501
8502                                 /*
8503                                  * An unvalidated constraint needs to be dumped separately, so
8504                                  * that potentially-violating existing data is loaded before
8505                                  * the constraint.
8506                                  */
8507                                 constrs[j].separate = !validated;
8508
8509                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8510
8511                                 /*
8512                                  * Mark the constraint as needing to appear before the table
8513                                  * --- this is so that any other dependencies of the
8514                                  * constraint will be emitted before we try to create the
8515                                  * table.  If the constraint is to be dumped separately, it
8516                                  * will be dumped after data is loaded anyway, so don't do it.
8517                                  * (There's an automatic dependency in the opposite direction
8518                                  * anyway, so don't need to add one manually here.)
8519                                  */
8520                                 if (!constrs[j].separate)
8521                                         addObjectDependency(&tbinfo->dobj,
8522                                                                                 constrs[j].dobj.dumpId);
8523
8524                                 /*
8525                                  * If the constraint is inherited, this will be detected later
8526                                  * (in pre-8.4 databases).  We also detect later if the
8527                                  * constraint must be split out from the table definition.
8528                                  */
8529                         }
8530                         PQclear(res);
8531                 }
8532         }
8533
8534         destroyPQExpBuffer(q);
8535 }
8536
8537 /*
8538  * Test whether a column should be printed as part of table's CREATE TABLE.
8539  * Column number is zero-based.
8540  *
8541  * Normally this is always true, but it's false for dropped columns, as well
8542  * as those that were inherited without any local definition.  (If we print
8543  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8544  * However, in binary_upgrade mode, we must print all such columns anyway and
8545  * fix the attislocal/attisdropped state later, so as to keep control of the
8546  * physical column order.
8547  *
8548  * This function exists because there are scattered nonobvious places that
8549  * must be kept in sync with this decision.
8550  */
8551 bool
8552 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8553 {
8554         if (dopt->binary_upgrade)
8555                 return true;
8556         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8557 }
8558
8559
8560 /*
8561  * getTSParsers:
8562  *        read all text search parsers in the system catalogs and return them
8563  *        in the TSParserInfo* structure
8564  *
8565  *      numTSParsers is set to the number of parsers read in
8566  */
8567 TSParserInfo *
8568 getTSParsers(Archive *fout, int *numTSParsers)
8569 {
8570         PGresult   *res;
8571         int                     ntups;
8572         int                     i;
8573         PQExpBuffer query;
8574         TSParserInfo *prsinfo;
8575         int                     i_tableoid;
8576         int                     i_oid;
8577         int                     i_prsname;
8578         int                     i_prsnamespace;
8579         int                     i_prsstart;
8580         int                     i_prstoken;
8581         int                     i_prsend;
8582         int                     i_prsheadline;
8583         int                     i_prslextype;
8584
8585         /* Before 8.3, there is no built-in text search support */
8586         if (fout->remoteVersion < 80300)
8587         {
8588                 *numTSParsers = 0;
8589                 return NULL;
8590         }
8591
8592         query = createPQExpBuffer();
8593
8594         /*
8595          * find all text search objects, including builtin ones; we filter out
8596          * system-defined objects at dump-out time.
8597          */
8598
8599         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8600                                                  "prsstart::oid, prstoken::oid, "
8601                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8602                                                  "FROM pg_ts_parser");
8603
8604         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8605
8606         ntups = PQntuples(res);
8607         *numTSParsers = ntups;
8608
8609         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8610
8611         i_tableoid = PQfnumber(res, "tableoid");
8612         i_oid = PQfnumber(res, "oid");
8613         i_prsname = PQfnumber(res, "prsname");
8614         i_prsnamespace = PQfnumber(res, "prsnamespace");
8615         i_prsstart = PQfnumber(res, "prsstart");
8616         i_prstoken = PQfnumber(res, "prstoken");
8617         i_prsend = PQfnumber(res, "prsend");
8618         i_prsheadline = PQfnumber(res, "prsheadline");
8619         i_prslextype = PQfnumber(res, "prslextype");
8620
8621         for (i = 0; i < ntups; i++)
8622         {
8623                 prsinfo[i].dobj.objType = DO_TSPARSER;
8624                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8625                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8626                 AssignDumpId(&prsinfo[i].dobj);
8627                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8628                 prsinfo[i].dobj.namespace =
8629                         findNamespace(fout,
8630                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8631                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8632                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8633                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8634                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8635                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8636
8637                 /* Decide whether we want to dump it */
8638                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8639
8640                 /* Text Search Parsers do not currently have ACLs. */
8641                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8642         }
8643
8644         PQclear(res);
8645
8646         destroyPQExpBuffer(query);
8647
8648         return prsinfo;
8649 }
8650
8651 /*
8652  * getTSDictionaries:
8653  *        read all text search dictionaries in the system catalogs and return them
8654  *        in the TSDictInfo* structure
8655  *
8656  *      numTSDicts is set to the number of dictionaries read in
8657  */
8658 TSDictInfo *
8659 getTSDictionaries(Archive *fout, int *numTSDicts)
8660 {
8661         PGresult   *res;
8662         int                     ntups;
8663         int                     i;
8664         PQExpBuffer query;
8665         TSDictInfo *dictinfo;
8666         int                     i_tableoid;
8667         int                     i_oid;
8668         int                     i_dictname;
8669         int                     i_dictnamespace;
8670         int                     i_rolname;
8671         int                     i_dicttemplate;
8672         int                     i_dictinitoption;
8673
8674         /* Before 8.3, there is no built-in text search support */
8675         if (fout->remoteVersion < 80300)
8676         {
8677                 *numTSDicts = 0;
8678                 return NULL;
8679         }
8680
8681         query = createPQExpBuffer();
8682
8683         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8684                                           "dictnamespace, (%s dictowner) AS rolname, "
8685                                           "dicttemplate, dictinitoption "
8686                                           "FROM pg_ts_dict",
8687                                           username_subquery);
8688
8689         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8690
8691         ntups = PQntuples(res);
8692         *numTSDicts = ntups;
8693
8694         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8695
8696         i_tableoid = PQfnumber(res, "tableoid");
8697         i_oid = PQfnumber(res, "oid");
8698         i_dictname = PQfnumber(res, "dictname");
8699         i_dictnamespace = PQfnumber(res, "dictnamespace");
8700         i_rolname = PQfnumber(res, "rolname");
8701         i_dictinitoption = PQfnumber(res, "dictinitoption");
8702         i_dicttemplate = PQfnumber(res, "dicttemplate");
8703
8704         for (i = 0; i < ntups; i++)
8705         {
8706                 dictinfo[i].dobj.objType = DO_TSDICT;
8707                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8708                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8709                 AssignDumpId(&dictinfo[i].dobj);
8710                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8711                 dictinfo[i].dobj.namespace =
8712                         findNamespace(fout,
8713                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8714                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8715                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8716                 if (PQgetisnull(res, i, i_dictinitoption))
8717                         dictinfo[i].dictinitoption = NULL;
8718                 else
8719                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8720
8721                 /* Decide whether we want to dump it */
8722                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8723
8724                 /* Text Search Dictionaries do not currently have ACLs. */
8725                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8726         }
8727
8728         PQclear(res);
8729
8730         destroyPQExpBuffer(query);
8731
8732         return dictinfo;
8733 }
8734
8735 /*
8736  * getTSTemplates:
8737  *        read all text search templates in the system catalogs and return them
8738  *        in the TSTemplateInfo* structure
8739  *
8740  *      numTSTemplates is set to the number of templates read in
8741  */
8742 TSTemplateInfo *
8743 getTSTemplates(Archive *fout, int *numTSTemplates)
8744 {
8745         PGresult   *res;
8746         int                     ntups;
8747         int                     i;
8748         PQExpBuffer query;
8749         TSTemplateInfo *tmplinfo;
8750         int                     i_tableoid;
8751         int                     i_oid;
8752         int                     i_tmplname;
8753         int                     i_tmplnamespace;
8754         int                     i_tmplinit;
8755         int                     i_tmpllexize;
8756
8757         /* Before 8.3, there is no built-in text search support */
8758         if (fout->remoteVersion < 80300)
8759         {
8760                 *numTSTemplates = 0;
8761                 return NULL;
8762         }
8763
8764         query = createPQExpBuffer();
8765
8766         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8767                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8768                                                  "FROM pg_ts_template");
8769
8770         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8771
8772         ntups = PQntuples(res);
8773         *numTSTemplates = ntups;
8774
8775         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8776
8777         i_tableoid = PQfnumber(res, "tableoid");
8778         i_oid = PQfnumber(res, "oid");
8779         i_tmplname = PQfnumber(res, "tmplname");
8780         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8781         i_tmplinit = PQfnumber(res, "tmplinit");
8782         i_tmpllexize = PQfnumber(res, "tmpllexize");
8783
8784         for (i = 0; i < ntups; i++)
8785         {
8786                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8787                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8788                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8789                 AssignDumpId(&tmplinfo[i].dobj);
8790                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8791                 tmplinfo[i].dobj.namespace =
8792                         findNamespace(fout,
8793                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8794                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8795                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8796
8797                 /* Decide whether we want to dump it */
8798                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8799
8800                 /* Text Search Templates do not currently have ACLs. */
8801                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8802         }
8803
8804         PQclear(res);
8805
8806         destroyPQExpBuffer(query);
8807
8808         return tmplinfo;
8809 }
8810
8811 /*
8812  * getTSConfigurations:
8813  *        read all text search configurations in the system catalogs and return
8814  *        them in the TSConfigInfo* structure
8815  *
8816  *      numTSConfigs is set to the number of configurations read in
8817  */
8818 TSConfigInfo *
8819 getTSConfigurations(Archive *fout, int *numTSConfigs)
8820 {
8821         PGresult   *res;
8822         int                     ntups;
8823         int                     i;
8824         PQExpBuffer query;
8825         TSConfigInfo *cfginfo;
8826         int                     i_tableoid;
8827         int                     i_oid;
8828         int                     i_cfgname;
8829         int                     i_cfgnamespace;
8830         int                     i_rolname;
8831         int                     i_cfgparser;
8832
8833         /* Before 8.3, there is no built-in text search support */
8834         if (fout->remoteVersion < 80300)
8835         {
8836                 *numTSConfigs = 0;
8837                 return NULL;
8838         }
8839
8840         query = createPQExpBuffer();
8841
8842         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8843                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8844                                           "FROM pg_ts_config",
8845                                           username_subquery);
8846
8847         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8848
8849         ntups = PQntuples(res);
8850         *numTSConfigs = ntups;
8851
8852         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8853
8854         i_tableoid = PQfnumber(res, "tableoid");
8855         i_oid = PQfnumber(res, "oid");
8856         i_cfgname = PQfnumber(res, "cfgname");
8857         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8858         i_rolname = PQfnumber(res, "rolname");
8859         i_cfgparser = PQfnumber(res, "cfgparser");
8860
8861         for (i = 0; i < ntups; i++)
8862         {
8863                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8864                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8865                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8866                 AssignDumpId(&cfginfo[i].dobj);
8867                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8868                 cfginfo[i].dobj.namespace =
8869                         findNamespace(fout,
8870                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8871                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8872                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8873
8874                 /* Decide whether we want to dump it */
8875                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8876
8877                 /* Text Search Configurations do not currently have ACLs. */
8878                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8879         }
8880
8881         PQclear(res);
8882
8883         destroyPQExpBuffer(query);
8884
8885         return cfginfo;
8886 }
8887
8888 /*
8889  * getForeignDataWrappers:
8890  *        read all foreign-data wrappers in the system catalogs and return
8891  *        them in the FdwInfo* structure
8892  *
8893  *      numForeignDataWrappers is set to the number of fdws read in
8894  */
8895 FdwInfo *
8896 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8897 {
8898         DumpOptions *dopt = fout->dopt;
8899         PGresult   *res;
8900         int                     ntups;
8901         int                     i;
8902         PQExpBuffer query;
8903         FdwInfo    *fdwinfo;
8904         int                     i_tableoid;
8905         int                     i_oid;
8906         int                     i_fdwname;
8907         int                     i_rolname;
8908         int                     i_fdwhandler;
8909         int                     i_fdwvalidator;
8910         int                     i_fdwacl;
8911         int                     i_rfdwacl;
8912         int                     i_initfdwacl;
8913         int                     i_initrfdwacl;
8914         int                     i_fdwoptions;
8915
8916         /* Before 8.4, there are no foreign-data wrappers */
8917         if (fout->remoteVersion < 80400)
8918         {
8919                 *numForeignDataWrappers = 0;
8920                 return NULL;
8921         }
8922
8923         query = createPQExpBuffer();
8924
8925         if (fout->remoteVersion >= 90600)
8926         {
8927                 PQExpBuffer acl_subquery = createPQExpBuffer();
8928                 PQExpBuffer racl_subquery = createPQExpBuffer();
8929                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8930                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8931
8932                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8933                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8934                                                 dopt->binary_upgrade);
8935
8936                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8937                                                   "(%s f.fdwowner) AS rolname, "
8938                                                   "f.fdwhandler::pg_catalog.regproc, "
8939                                                   "f.fdwvalidator::pg_catalog.regproc, "
8940                                                   "%s AS fdwacl, "
8941                                                   "%s AS rfdwacl, "
8942                                                   "%s AS initfdwacl, "
8943                                                   "%s AS initrfdwacl, "
8944                                                   "array_to_string(ARRAY("
8945                                                   "SELECT quote_ident(option_name) || ' ' || "
8946                                                   "quote_literal(option_value) "
8947                                                   "FROM pg_options_to_table(f.fdwoptions) "
8948                                                   "ORDER BY option_name"
8949                                                   "), E',\n    ') AS fdwoptions "
8950                                                   "FROM pg_foreign_data_wrapper f "
8951                                                   "LEFT JOIN pg_init_privs pip ON "
8952                                                   "(f.oid = pip.objoid "
8953                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8954                                                   "AND pip.objsubid = 0) ",
8955                                                   username_subquery,
8956                                                   acl_subquery->data,
8957                                                   racl_subquery->data,
8958                                                   initacl_subquery->data,
8959                                                   initracl_subquery->data);
8960
8961                 destroyPQExpBuffer(acl_subquery);
8962                 destroyPQExpBuffer(racl_subquery);
8963                 destroyPQExpBuffer(initacl_subquery);
8964                 destroyPQExpBuffer(initracl_subquery);
8965         }
8966         else if (fout->remoteVersion >= 90100)
8967         {
8968                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8969                                                   "(%s fdwowner) AS rolname, "
8970                                                   "fdwhandler::pg_catalog.regproc, "
8971                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8972                                                   "NULL as rfdwacl, "
8973                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8974                                                   "array_to_string(ARRAY("
8975                                                   "SELECT quote_ident(option_name) || ' ' || "
8976                                                   "quote_literal(option_value) "
8977                                                   "FROM pg_options_to_table(fdwoptions) "
8978                                                   "ORDER BY option_name"
8979                                                   "), E',\n    ') AS fdwoptions "
8980                                                   "FROM pg_foreign_data_wrapper",
8981                                                   username_subquery);
8982         }
8983         else
8984         {
8985                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8986                                                   "(%s fdwowner) AS rolname, "
8987                                                   "'-' AS fdwhandler, "
8988                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8989                                                   "NULL as rfdwacl, "
8990                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8991                                                   "array_to_string(ARRAY("
8992                                                   "SELECT quote_ident(option_name) || ' ' || "
8993                                                   "quote_literal(option_value) "
8994                                                   "FROM pg_options_to_table(fdwoptions) "
8995                                                   "ORDER BY option_name"
8996                                                   "), E',\n    ') AS fdwoptions "
8997                                                   "FROM pg_foreign_data_wrapper",
8998                                                   username_subquery);
8999         }
9000
9001         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9002
9003         ntups = PQntuples(res);
9004         *numForeignDataWrappers = ntups;
9005
9006         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9007
9008         i_tableoid = PQfnumber(res, "tableoid");
9009         i_oid = PQfnumber(res, "oid");
9010         i_fdwname = PQfnumber(res, "fdwname");
9011         i_rolname = PQfnumber(res, "rolname");
9012         i_fdwhandler = PQfnumber(res, "fdwhandler");
9013         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9014         i_fdwacl = PQfnumber(res, "fdwacl");
9015         i_rfdwacl = PQfnumber(res, "rfdwacl");
9016         i_initfdwacl = PQfnumber(res, "initfdwacl");
9017         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9018         i_fdwoptions = PQfnumber(res, "fdwoptions");
9019
9020         for (i = 0; i < ntups; i++)
9021         {
9022                 fdwinfo[i].dobj.objType = DO_FDW;
9023                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9024                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9025                 AssignDumpId(&fdwinfo[i].dobj);
9026                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9027                 fdwinfo[i].dobj.namespace = NULL;
9028                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9029                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9030                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9031                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9032                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9033                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9034                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9035                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9036
9037                 /* Decide whether we want to dump it */
9038                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9039
9040                 /* Do not try to dump ACL if no ACL exists. */
9041                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9042                         PQgetisnull(res, i, i_initfdwacl) &&
9043                         PQgetisnull(res, i, i_initrfdwacl))
9044                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9045         }
9046
9047         PQclear(res);
9048
9049         destroyPQExpBuffer(query);
9050
9051         return fdwinfo;
9052 }
9053
9054 /*
9055  * getForeignServers:
9056  *        read all foreign servers in the system catalogs and return
9057  *        them in the ForeignServerInfo * structure
9058  *
9059  *      numForeignServers is set to the number of servers read in
9060  */
9061 ForeignServerInfo *
9062 getForeignServers(Archive *fout, int *numForeignServers)
9063 {
9064         DumpOptions *dopt = fout->dopt;
9065         PGresult   *res;
9066         int                     ntups;
9067         int                     i;
9068         PQExpBuffer query;
9069         ForeignServerInfo *srvinfo;
9070         int                     i_tableoid;
9071         int                     i_oid;
9072         int                     i_srvname;
9073         int                     i_rolname;
9074         int                     i_srvfdw;
9075         int                     i_srvtype;
9076         int                     i_srvversion;
9077         int                     i_srvacl;
9078         int                     i_rsrvacl;
9079         int                     i_initsrvacl;
9080         int                     i_initrsrvacl;
9081         int                     i_srvoptions;
9082
9083         /* Before 8.4, there are no foreign servers */
9084         if (fout->remoteVersion < 80400)
9085         {
9086                 *numForeignServers = 0;
9087                 return NULL;
9088         }
9089
9090         query = createPQExpBuffer();
9091
9092         if (fout->remoteVersion >= 90600)
9093         {
9094                 PQExpBuffer acl_subquery = createPQExpBuffer();
9095                 PQExpBuffer racl_subquery = createPQExpBuffer();
9096                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9097                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9098
9099                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9100                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9101                                                 dopt->binary_upgrade);
9102
9103                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9104                                                   "(%s f.srvowner) AS rolname, "
9105                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9106                                                   "%s AS srvacl, "
9107                                                   "%s AS rsrvacl, "
9108                                                   "%s AS initsrvacl, "
9109                                                   "%s AS initrsrvacl, "
9110                                                   "array_to_string(ARRAY("
9111                                                   "SELECT quote_ident(option_name) || ' ' || "
9112                                                   "quote_literal(option_value) "
9113                                                   "FROM pg_options_to_table(f.srvoptions) "
9114                                                   "ORDER BY option_name"
9115                                                   "), E',\n    ') AS srvoptions "
9116                                                   "FROM pg_foreign_server f "
9117                                                   "LEFT JOIN pg_init_privs pip "
9118                                                   "ON (f.oid = pip.objoid "
9119                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9120                                                   "AND pip.objsubid = 0) ",
9121                                                   username_subquery,
9122                                                   acl_subquery->data,
9123                                                   racl_subquery->data,
9124                                                   initacl_subquery->data,
9125                                                   initracl_subquery->data);
9126
9127                 destroyPQExpBuffer(acl_subquery);
9128                 destroyPQExpBuffer(racl_subquery);
9129                 destroyPQExpBuffer(initacl_subquery);
9130                 destroyPQExpBuffer(initracl_subquery);
9131         }
9132         else
9133         {
9134                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9135                                                   "(%s srvowner) AS rolname, "
9136                                                   "srvfdw, srvtype, srvversion, srvacl, "
9137                                                   "NULL AS rsrvacl, "
9138                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9139                                                   "array_to_string(ARRAY("
9140                                                   "SELECT quote_ident(option_name) || ' ' || "
9141                                                   "quote_literal(option_value) "
9142                                                   "FROM pg_options_to_table(srvoptions) "
9143                                                   "ORDER BY option_name"
9144                                                   "), E',\n    ') AS srvoptions "
9145                                                   "FROM pg_foreign_server",
9146                                                   username_subquery);
9147         }
9148
9149         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9150
9151         ntups = PQntuples(res);
9152         *numForeignServers = ntups;
9153
9154         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9155
9156         i_tableoid = PQfnumber(res, "tableoid");
9157         i_oid = PQfnumber(res, "oid");
9158         i_srvname = PQfnumber(res, "srvname");
9159         i_rolname = PQfnumber(res, "rolname");
9160         i_srvfdw = PQfnumber(res, "srvfdw");
9161         i_srvtype = PQfnumber(res, "srvtype");
9162         i_srvversion = PQfnumber(res, "srvversion");
9163         i_srvacl = PQfnumber(res, "srvacl");
9164         i_rsrvacl = PQfnumber(res, "rsrvacl");
9165         i_initsrvacl = PQfnumber(res, "initsrvacl");
9166         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9167         i_srvoptions = PQfnumber(res, "srvoptions");
9168
9169         for (i = 0; i < ntups; i++)
9170         {
9171                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9172                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9173                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9174                 AssignDumpId(&srvinfo[i].dobj);
9175                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9176                 srvinfo[i].dobj.namespace = NULL;
9177                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9178                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9179                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9180                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9181                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9182                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9183                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9184                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9185                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9186
9187                 /* Decide whether we want to dump it */
9188                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9189
9190                 /* Do not try to dump ACL if no ACL exists. */
9191                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9192                         PQgetisnull(res, i, i_initsrvacl) &&
9193                         PQgetisnull(res, i, i_initrsrvacl))
9194                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9195         }
9196
9197         PQclear(res);
9198
9199         destroyPQExpBuffer(query);
9200
9201         return srvinfo;
9202 }
9203
9204 /*
9205  * getDefaultACLs:
9206  *        read all default ACL information in the system catalogs and return
9207  *        them in the DefaultACLInfo structure
9208  *
9209  *      numDefaultACLs is set to the number of ACLs read in
9210  */
9211 DefaultACLInfo *
9212 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9213 {
9214         DumpOptions *dopt = fout->dopt;
9215         DefaultACLInfo *daclinfo;
9216         PQExpBuffer query;
9217         PGresult   *res;
9218         int                     i_oid;
9219         int                     i_tableoid;
9220         int                     i_defaclrole;
9221         int                     i_defaclnamespace;
9222         int                     i_defaclobjtype;
9223         int                     i_defaclacl;
9224         int                     i_rdefaclacl;
9225         int                     i_initdefaclacl;
9226         int                     i_initrdefaclacl;
9227         int                     i,
9228                                 ntups;
9229
9230         if (fout->remoteVersion < 90000)
9231         {
9232                 *numDefaultACLs = 0;
9233                 return NULL;
9234         }
9235
9236         query = createPQExpBuffer();
9237
9238         if (fout->remoteVersion >= 90600)
9239         {
9240                 PQExpBuffer acl_subquery = createPQExpBuffer();
9241                 PQExpBuffer racl_subquery = createPQExpBuffer();
9242                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9243                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9244
9245                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9246                                                 initracl_subquery, "defaclacl", "defaclrole",
9247                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9248                                                 dopt->binary_upgrade);
9249
9250                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9251                                                   "(%s d.defaclrole) AS defaclrole, "
9252                                                   "d.defaclnamespace, "
9253                                                   "d.defaclobjtype, "
9254                                                   "%s AS defaclacl, "
9255                                                   "%s AS rdefaclacl, "
9256                                                   "%s AS initdefaclacl, "
9257                                                   "%s AS initrdefaclacl "
9258                                                   "FROM pg_default_acl d "
9259                                                   "LEFT JOIN pg_init_privs pip ON "
9260                                                   "(d.oid = pip.objoid "
9261                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9262                                                   "AND pip.objsubid = 0) ",
9263                                                   username_subquery,
9264                                                   acl_subquery->data,
9265                                                   racl_subquery->data,
9266                                                   initacl_subquery->data,
9267                                                   initracl_subquery->data);
9268         }
9269         else
9270         {
9271                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9272                                                   "(%s defaclrole) AS defaclrole, "
9273                                                   "defaclnamespace, "
9274                                                   "defaclobjtype, "
9275                                                   "defaclacl, "
9276                                                   "NULL AS rdefaclacl, "
9277                                                   "NULL AS initdefaclacl, "
9278                                                   "NULL AS initrdefaclacl "
9279                                                   "FROM pg_default_acl",
9280                                                   username_subquery);
9281         }
9282
9283         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9284
9285         ntups = PQntuples(res);
9286         *numDefaultACLs = ntups;
9287
9288         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9289
9290         i_oid = PQfnumber(res, "oid");
9291         i_tableoid = PQfnumber(res, "tableoid");
9292         i_defaclrole = PQfnumber(res, "defaclrole");
9293         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9294         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9295         i_defaclacl = PQfnumber(res, "defaclacl");
9296         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9297         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9298         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9299
9300         for (i = 0; i < ntups; i++)
9301         {
9302                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9303
9304                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9305                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9306                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9307                 AssignDumpId(&daclinfo[i].dobj);
9308                 /* cheesy ... is it worth coming up with a better object name? */
9309                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9310
9311                 if (nspid != InvalidOid)
9312                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9313                 else
9314                         daclinfo[i].dobj.namespace = NULL;
9315
9316                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9317                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9318                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9319                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9320                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9321                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9322
9323                 /* Decide whether we want to dump it */
9324                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9325         }
9326
9327         PQclear(res);
9328
9329         destroyPQExpBuffer(query);
9330
9331         return daclinfo;
9332 }
9333
9334 /*
9335  * dumpComment --
9336  *
9337  * This routine is used to dump any comments associated with the
9338  * object handed to this routine. The routine takes the object type
9339  * and object name (ready to print, except for schema decoration), plus
9340  * the namespace and owner of the object (for labeling the ArchiveEntry),
9341  * plus catalog ID and subid which are the lookup key for pg_description,
9342  * plus the dump ID for the object (for setting a dependency).
9343  * If a matching pg_description entry is found, it is dumped.
9344  *
9345  * Note: in some cases, such as comments for triggers and rules, the "type"
9346  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9347  * but it doesn't seem worth complicating the API for all callers to make
9348  * it cleaner.
9349  *
9350  * Note: although this routine takes a dumpId for dependency purposes,
9351  * that purpose is just to mark the dependency in the emitted dump file
9352  * for possible future use by pg_restore.  We do NOT use it for determining
9353  * ordering of the comment in the dump file, because this routine is called
9354  * after dependency sorting occurs.  This routine should be called just after
9355  * calling ArchiveEntry() for the specified object.
9356  */
9357 static void
9358 dumpComment(Archive *fout, const char *type, const char *name,
9359                         const char *namespace, const char *owner,
9360                         CatalogId catalogId, int subid, DumpId dumpId)
9361 {
9362         DumpOptions *dopt = fout->dopt;
9363         CommentItem *comments;
9364         int                     ncomments;
9365
9366         /* do nothing, if --no-comments is supplied */
9367         if (dopt->no_comments)
9368                 return;
9369
9370         /* Comments are schema not data ... except blob comments are data */
9371         if (strcmp(type, "LARGE OBJECT") != 0)
9372         {
9373                 if (dopt->dataOnly)
9374                         return;
9375         }
9376         else
9377         {
9378                 /* We do dump blob comments in binary-upgrade mode */
9379                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9380                         return;
9381         }
9382
9383         /* Search for comments associated with catalogId, using table */
9384         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9385                                                          &comments);
9386
9387         /* Is there one matching the subid? */
9388         while (ncomments > 0)
9389         {
9390                 if (comments->objsubid == subid)
9391                         break;
9392                 comments++;
9393                 ncomments--;
9394         }
9395
9396         /* If a comment exists, build COMMENT ON statement */
9397         if (ncomments > 0)
9398         {
9399                 PQExpBuffer query = createPQExpBuffer();
9400                 PQExpBuffer tag = createPQExpBuffer();
9401
9402                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9403                 if (namespace && *namespace)
9404                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9405                 appendPQExpBuffer(query, "%s IS ", name);
9406                 appendStringLiteralAH(query, comments->descr, fout);
9407                 appendPQExpBufferStr(query, ";\n");
9408
9409                 appendPQExpBuffer(tag, "%s %s", type, name);
9410
9411                 /*
9412                  * We mark comments as SECTION_NONE because they really belong in the
9413                  * same section as their parent, whether that is pre-data or
9414                  * post-data.
9415                  */
9416                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9417                                          tag->data, namespace, NULL, owner,
9418                                          false, "COMMENT", SECTION_NONE,
9419                                          query->data, "", NULL,
9420                                          &(dumpId), 1,
9421                                          NULL, NULL);
9422
9423                 destroyPQExpBuffer(query);
9424                 destroyPQExpBuffer(tag);
9425         }
9426 }
9427
9428 /*
9429  * dumpTableComment --
9430  *
9431  * As above, but dump comments for both the specified table (or view)
9432  * and its columns.
9433  */
9434 static void
9435 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9436                                  const char *reltypename)
9437 {
9438         DumpOptions *dopt = fout->dopt;
9439         CommentItem *comments;
9440         int                     ncomments;
9441         PQExpBuffer query;
9442         PQExpBuffer tag;
9443
9444         /* do nothing, if --no-comments is supplied */
9445         if (dopt->no_comments)
9446                 return;
9447
9448         /* Comments are SCHEMA not data */
9449         if (dopt->dataOnly)
9450                 return;
9451
9452         /* Search for comments associated with relation, using table */
9453         ncomments = findComments(fout,
9454                                                          tbinfo->dobj.catId.tableoid,
9455                                                          tbinfo->dobj.catId.oid,
9456                                                          &comments);
9457
9458         /* If comments exist, build COMMENT ON statements */
9459         if (ncomments <= 0)
9460                 return;
9461
9462         query = createPQExpBuffer();
9463         tag = createPQExpBuffer();
9464
9465         while (ncomments > 0)
9466         {
9467                 const char *descr = comments->descr;
9468                 int                     objsubid = comments->objsubid;
9469
9470                 if (objsubid == 0)
9471                 {
9472                         resetPQExpBuffer(tag);
9473                         appendPQExpBuffer(tag, "%s %s", reltypename,
9474                                                           fmtId(tbinfo->dobj.name));
9475
9476                         resetPQExpBuffer(query);
9477                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9478                                                           fmtQualifiedDumpable(tbinfo));
9479                         appendStringLiteralAH(query, descr, fout);
9480                         appendPQExpBufferStr(query, ";\n");
9481
9482                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9483                                                  tag->data,
9484                                                  tbinfo->dobj.namespace->dobj.name,
9485                                                  NULL, tbinfo->rolname,
9486                                                  false, "COMMENT", SECTION_NONE,
9487                                                  query->data, "", NULL,
9488                                                  &(tbinfo->dobj.dumpId), 1,
9489                                                  NULL, NULL);
9490                 }
9491                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9492                 {
9493                         resetPQExpBuffer(tag);
9494                         appendPQExpBuffer(tag, "COLUMN %s.",
9495                                                           fmtId(tbinfo->dobj.name));
9496                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9497
9498                         resetPQExpBuffer(query);
9499                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9500                                                           fmtQualifiedDumpable(tbinfo));
9501                         appendPQExpBuffer(query, "%s IS ",
9502                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9503                         appendStringLiteralAH(query, descr, fout);
9504                         appendPQExpBufferStr(query, ";\n");
9505
9506                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9507                                                  tag->data,
9508                                                  tbinfo->dobj.namespace->dobj.name,
9509                                                  NULL, tbinfo->rolname,
9510                                                  false, "COMMENT", SECTION_NONE,
9511                                                  query->data, "", NULL,
9512                                                  &(tbinfo->dobj.dumpId), 1,
9513                                                  NULL, NULL);
9514                 }
9515
9516                 comments++;
9517                 ncomments--;
9518         }
9519
9520         destroyPQExpBuffer(query);
9521         destroyPQExpBuffer(tag);
9522 }
9523
9524 /*
9525  * findComments --
9526  *
9527  * Find the comment(s), if any, associated with the given object.  All the
9528  * objsubid values associated with the given classoid/objoid are found with
9529  * one search.
9530  */
9531 static int
9532 findComments(Archive *fout, Oid classoid, Oid objoid,
9533                          CommentItem **items)
9534 {
9535         /* static storage for table of comments */
9536         static CommentItem *comments = NULL;
9537         static int      ncomments = -1;
9538
9539         CommentItem *middle = NULL;
9540         CommentItem *low;
9541         CommentItem *high;
9542         int                     nmatch;
9543
9544         /* Get comments if we didn't already */
9545         if (ncomments < 0)
9546                 ncomments = collectComments(fout, &comments);
9547
9548         /*
9549          * Do binary search to find some item matching the object.
9550          */
9551         low = &comments[0];
9552         high = &comments[ncomments - 1];
9553         while (low <= high)
9554         {
9555                 middle = low + (high - low) / 2;
9556
9557                 if (classoid < middle->classoid)
9558                         high = middle - 1;
9559                 else if (classoid > middle->classoid)
9560                         low = middle + 1;
9561                 else if (objoid < middle->objoid)
9562                         high = middle - 1;
9563                 else if (objoid > middle->objoid)
9564                         low = middle + 1;
9565                 else
9566                         break;                          /* found a match */
9567         }
9568
9569         if (low > high)                         /* no matches */
9570         {
9571                 *items = NULL;
9572                 return 0;
9573         }
9574
9575         /*
9576          * Now determine how many items match the object.  The search loop
9577          * invariant still holds: only items between low and high inclusive could
9578          * match.
9579          */
9580         nmatch = 1;
9581         while (middle > low)
9582         {
9583                 if (classoid != middle[-1].classoid ||
9584                         objoid != middle[-1].objoid)
9585                         break;
9586                 middle--;
9587                 nmatch++;
9588         }
9589
9590         *items = middle;
9591
9592         middle += nmatch;
9593         while (middle <= high)
9594         {
9595                 if (classoid != middle->classoid ||
9596                         objoid != middle->objoid)
9597                         break;
9598                 middle++;
9599                 nmatch++;
9600         }
9601
9602         return nmatch;
9603 }
9604
9605 /*
9606  * collectComments --
9607  *
9608  * Construct a table of all comments available for database objects.
9609  * We used to do per-object queries for the comments, but it's much faster
9610  * to pull them all over at once, and on most databases the memory cost
9611  * isn't high.
9612  *
9613  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9614  */
9615 static int
9616 collectComments(Archive *fout, CommentItem **items)
9617 {
9618         PGresult   *res;
9619         PQExpBuffer query;
9620         int                     i_description;
9621         int                     i_classoid;
9622         int                     i_objoid;
9623         int                     i_objsubid;
9624         int                     ntups;
9625         int                     i;
9626         CommentItem *comments;
9627
9628         query = createPQExpBuffer();
9629
9630         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9631                                                  "FROM pg_catalog.pg_description "
9632                                                  "ORDER BY classoid, objoid, objsubid");
9633
9634         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9635
9636         /* Construct lookup table containing OIDs in numeric form */
9637
9638         i_description = PQfnumber(res, "description");
9639         i_classoid = PQfnumber(res, "classoid");
9640         i_objoid = PQfnumber(res, "objoid");
9641         i_objsubid = PQfnumber(res, "objsubid");
9642
9643         ntups = PQntuples(res);
9644
9645         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9646
9647         for (i = 0; i < ntups; i++)
9648         {
9649                 comments[i].descr = PQgetvalue(res, i, i_description);
9650                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9651                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9652                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9653         }
9654
9655         /* Do NOT free the PGresult since we are keeping pointers into it */
9656         destroyPQExpBuffer(query);
9657
9658         *items = comments;
9659         return ntups;
9660 }
9661
9662 /*
9663  * dumpDumpableObject
9664  *
9665  * This routine and its subsidiaries are responsible for creating
9666  * ArchiveEntries (TOC objects) for each object to be dumped.
9667  */
9668 static void
9669 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9670 {
9671         switch (dobj->objType)
9672         {
9673                 case DO_NAMESPACE:
9674                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9675                         break;
9676                 case DO_EXTENSION:
9677                         dumpExtension(fout, (ExtensionInfo *) dobj);
9678                         break;
9679                 case DO_TYPE:
9680                         dumpType(fout, (TypeInfo *) dobj);
9681                         break;
9682                 case DO_SHELL_TYPE:
9683                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9684                         break;
9685                 case DO_FUNC:
9686                         dumpFunc(fout, (FuncInfo *) dobj);
9687                         break;
9688                 case DO_AGG:
9689                         dumpAgg(fout, (AggInfo *) dobj);
9690                         break;
9691                 case DO_OPERATOR:
9692                         dumpOpr(fout, (OprInfo *) dobj);
9693                         break;
9694                 case DO_ACCESS_METHOD:
9695                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9696                         break;
9697                 case DO_OPCLASS:
9698                         dumpOpclass(fout, (OpclassInfo *) dobj);
9699                         break;
9700                 case DO_OPFAMILY:
9701                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9702                         break;
9703                 case DO_COLLATION:
9704                         dumpCollation(fout, (CollInfo *) dobj);
9705                         break;
9706                 case DO_CONVERSION:
9707                         dumpConversion(fout, (ConvInfo *) dobj);
9708                         break;
9709                 case DO_TABLE:
9710                         dumpTable(fout, (TableInfo *) dobj);
9711                         break;
9712                 case DO_ATTRDEF:
9713                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9714                         break;
9715                 case DO_INDEX:
9716                         dumpIndex(fout, (IndxInfo *) dobj);
9717                         break;
9718                 case DO_INDEX_ATTACH:
9719                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9720                         break;
9721                 case DO_STATSEXT:
9722                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9723                         break;
9724                 case DO_REFRESH_MATVIEW:
9725                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9726                         break;
9727                 case DO_RULE:
9728                         dumpRule(fout, (RuleInfo *) dobj);
9729                         break;
9730                 case DO_TRIGGER:
9731                         dumpTrigger(fout, (TriggerInfo *) dobj);
9732                         break;
9733                 case DO_EVENT_TRIGGER:
9734                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9735                         break;
9736                 case DO_CONSTRAINT:
9737                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9738                         break;
9739                 case DO_FK_CONSTRAINT:
9740                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9741                         break;
9742                 case DO_PROCLANG:
9743                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9744                         break;
9745                 case DO_CAST:
9746                         dumpCast(fout, (CastInfo *) dobj);
9747                         break;
9748                 case DO_TRANSFORM:
9749                         dumpTransform(fout, (TransformInfo *) dobj);
9750                         break;
9751                 case DO_SEQUENCE_SET:
9752                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9753                         break;
9754                 case DO_TABLE_DATA:
9755                         dumpTableData(fout, (TableDataInfo *) dobj);
9756                         break;
9757                 case DO_DUMMY_TYPE:
9758                         /* table rowtypes and array types are never dumped separately */
9759                         break;
9760                 case DO_TSPARSER:
9761                         dumpTSParser(fout, (TSParserInfo *) dobj);
9762                         break;
9763                 case DO_TSDICT:
9764                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9765                         break;
9766                 case DO_TSTEMPLATE:
9767                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9768                         break;
9769                 case DO_TSCONFIG:
9770                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9771                         break;
9772                 case DO_FDW:
9773                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9774                         break;
9775                 case DO_FOREIGN_SERVER:
9776                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9777                         break;
9778                 case DO_DEFAULT_ACL:
9779                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9780                         break;
9781                 case DO_BLOB:
9782                         dumpBlob(fout, (BlobInfo *) dobj);
9783                         break;
9784                 case DO_BLOB_DATA:
9785                         if (dobj->dump & DUMP_COMPONENT_DATA)
9786                         {
9787                                 TocEntry   *te;
9788
9789                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9790                                                                   dobj->name, NULL, NULL, "",
9791                                                                   false, "BLOBS", SECTION_DATA,
9792                                                                   "", "", NULL,
9793                                                                   NULL, 0,
9794                                                                   dumpBlobs, NULL);
9795
9796                                 /*
9797                                  * Set the TocEntry's dataLength in case we are doing a
9798                                  * parallel dump and want to order dump jobs by table size.
9799                                  * (We need some size estimate for every TocEntry with a
9800                                  * DataDumper function.)  We don't currently have any cheap
9801                                  * way to estimate the size of blobs, but it doesn't matter;
9802                                  * let's just set the size to a large value so parallel dumps
9803                                  * will launch this job first.  If there's lots of blobs, we
9804                                  * win, and if there aren't, we don't lose much.  (If you want
9805                                  * to improve on this, really what you should be thinking
9806                                  * about is allowing blob dumping to be parallelized, not just
9807                                  * getting a smarter estimate for the single TOC entry.)
9808                                  */
9809                                 te->dataLength = MaxBlockNumber;
9810                         }
9811                         break;
9812                 case DO_POLICY:
9813                         dumpPolicy(fout, (PolicyInfo *) dobj);
9814                         break;
9815                 case DO_PUBLICATION:
9816                         dumpPublication(fout, (PublicationInfo *) dobj);
9817                         break;
9818                 case DO_PUBLICATION_REL:
9819                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9820                         break;
9821                 case DO_SUBSCRIPTION:
9822                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9823                         break;
9824                 case DO_PRE_DATA_BOUNDARY:
9825                 case DO_POST_DATA_BOUNDARY:
9826                         /* never dumped, nothing to do */
9827                         break;
9828         }
9829 }
9830
9831 /*
9832  * dumpNamespace
9833  *        writes out to fout the queries to recreate a user-defined namespace
9834  */
9835 static void
9836 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9837 {
9838         DumpOptions *dopt = fout->dopt;
9839         PQExpBuffer q;
9840         PQExpBuffer delq;
9841         char       *qnspname;
9842
9843         /* Skip if not to be dumped */
9844         if (!nspinfo->dobj.dump || dopt->dataOnly)
9845                 return;
9846
9847         q = createPQExpBuffer();
9848         delq = createPQExpBuffer();
9849
9850         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9851
9852         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9853
9854         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9855
9856         if (dopt->binary_upgrade)
9857                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9858                                                                                 "SCHEMA", qnspname, NULL);
9859
9860         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9861                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9862                                          nspinfo->dobj.name,
9863                                          NULL, NULL,
9864                                          nspinfo->rolname,
9865                                          false, "SCHEMA", SECTION_PRE_DATA,
9866                                          q->data, delq->data, NULL,
9867                                          NULL, 0,
9868                                          NULL, NULL);
9869
9870         /* Dump Schema Comments and Security Labels */
9871         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9872                 dumpComment(fout, "SCHEMA", qnspname,
9873                                         NULL, nspinfo->rolname,
9874                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9875
9876         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9877                 dumpSecLabel(fout, "SCHEMA", qnspname,
9878                                          NULL, nspinfo->rolname,
9879                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9880
9881         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9882                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9883                                 qnspname, NULL, NULL,
9884                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9885                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9886
9887         free(qnspname);
9888
9889         destroyPQExpBuffer(q);
9890         destroyPQExpBuffer(delq);
9891 }
9892
9893 /*
9894  * dumpExtension
9895  *        writes out to fout the queries to recreate an extension
9896  */
9897 static void
9898 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9899 {
9900         DumpOptions *dopt = fout->dopt;
9901         PQExpBuffer q;
9902         PQExpBuffer delq;
9903         char       *qextname;
9904
9905         /* Skip if not to be dumped */
9906         if (!extinfo->dobj.dump || dopt->dataOnly)
9907                 return;
9908
9909         q = createPQExpBuffer();
9910         delq = createPQExpBuffer();
9911
9912         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9913
9914         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9915
9916         if (!dopt->binary_upgrade)
9917         {
9918                 /*
9919                  * In a regular dump, we simply create the extension, intentionally
9920                  * not specifying a version, so that the destination installation's
9921                  * default version is used.
9922                  *
9923                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9924                  * types; but there are various scenarios in which it's convenient to
9925                  * manually create the desired extension before restoring, so we
9926                  * prefer to allow it to exist already.
9927                  */
9928                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9929                                                   qextname, fmtId(extinfo->namespace));
9930         }
9931         else
9932         {
9933                 /*
9934                  * In binary-upgrade mode, it's critical to reproduce the state of the
9935                  * database exactly, so our procedure is to create an empty extension,
9936                  * restore all the contained objects normally, and add them to the
9937                  * extension one by one.  This function performs just the first of
9938                  * those steps.  binary_upgrade_extension_member() takes care of
9939                  * adding member objects as they're created.
9940                  */
9941                 int                     i;
9942                 int                     n;
9943
9944                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9945
9946                 /*
9947                  * We unconditionally create the extension, so we must drop it if it
9948                  * exists.  This could happen if the user deleted 'plpgsql' and then
9949                  * readded it, causing its oid to be greater than g_last_builtin_oid.
9950                  */
9951                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9952
9953                 appendPQExpBufferStr(q,
9954                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9955                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
9956                 appendPQExpBufferStr(q, ", ");
9957                 appendStringLiteralAH(q, extinfo->namespace, fout);
9958                 appendPQExpBufferStr(q, ", ");
9959                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9960                 appendStringLiteralAH(q, extinfo->extversion, fout);
9961                 appendPQExpBufferStr(q, ", ");
9962
9963                 /*
9964                  * Note that we're pushing extconfig (an OID array) back into
9965                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
9966                  * preserved in binary upgrade.
9967                  */
9968                 if (strlen(extinfo->extconfig) > 2)
9969                         appendStringLiteralAH(q, extinfo->extconfig, fout);
9970                 else
9971                         appendPQExpBufferStr(q, "NULL");
9972                 appendPQExpBufferStr(q, ", ");
9973                 if (strlen(extinfo->extcondition) > 2)
9974                         appendStringLiteralAH(q, extinfo->extcondition, fout);
9975                 else
9976                         appendPQExpBufferStr(q, "NULL");
9977                 appendPQExpBufferStr(q, ", ");
9978                 appendPQExpBufferStr(q, "ARRAY[");
9979                 n = 0;
9980                 for (i = 0; i < extinfo->dobj.nDeps; i++)
9981                 {
9982                         DumpableObject *extobj;
9983
9984                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9985                         if (extobj && extobj->objType == DO_EXTENSION)
9986                         {
9987                                 if (n++ > 0)
9988                                         appendPQExpBufferChar(q, ',');
9989                                 appendStringLiteralAH(q, extobj->name, fout);
9990                         }
9991                 }
9992                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9993                 appendPQExpBufferStr(q, ");\n");
9994         }
9995
9996         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9997                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9998                                          extinfo->dobj.name,
9999                                          NULL, NULL,
10000                                          "",
10001                                          false, "EXTENSION", SECTION_PRE_DATA,
10002                                          q->data, delq->data, NULL,
10003                                          NULL, 0,
10004                                          NULL, NULL);
10005
10006         /* Dump Extension Comments and Security Labels */
10007         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10008                 dumpComment(fout, "EXTENSION", qextname,
10009                                         NULL, "",
10010                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10011
10012         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10013                 dumpSecLabel(fout, "EXTENSION", qextname,
10014                                          NULL, "",
10015                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10016
10017         free(qextname);
10018
10019         destroyPQExpBuffer(q);
10020         destroyPQExpBuffer(delq);
10021 }
10022
10023 /*
10024  * dumpType
10025  *        writes out to fout the queries to recreate a user-defined type
10026  */
10027 static void
10028 dumpType(Archive *fout, TypeInfo *tyinfo)
10029 {
10030         DumpOptions *dopt = fout->dopt;
10031
10032         /* Skip if not to be dumped */
10033         if (!tyinfo->dobj.dump || dopt->dataOnly)
10034                 return;
10035
10036         /* Dump out in proper style */
10037         if (tyinfo->typtype == TYPTYPE_BASE)
10038                 dumpBaseType(fout, tyinfo);
10039         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10040                 dumpDomain(fout, tyinfo);
10041         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10042                 dumpCompositeType(fout, tyinfo);
10043         else if (tyinfo->typtype == TYPTYPE_ENUM)
10044                 dumpEnumType(fout, tyinfo);
10045         else if (tyinfo->typtype == TYPTYPE_RANGE)
10046                 dumpRangeType(fout, tyinfo);
10047         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10048                 dumpUndefinedType(fout, tyinfo);
10049         else
10050                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
10051                                   tyinfo->dobj.name);
10052 }
10053
10054 /*
10055  * dumpEnumType
10056  *        writes out to fout the queries to recreate a user-defined enum type
10057  */
10058 static void
10059 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10060 {
10061         DumpOptions *dopt = fout->dopt;
10062         PQExpBuffer q = createPQExpBuffer();
10063         PQExpBuffer delq = createPQExpBuffer();
10064         PQExpBuffer query = createPQExpBuffer();
10065         PGresult   *res;
10066         int                     num,
10067                                 i;
10068         Oid                     enum_oid;
10069         char       *qtypname;
10070         char       *qualtypname;
10071         char       *label;
10072
10073         if (fout->remoteVersion >= 90100)
10074                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10075                                                   "FROM pg_catalog.pg_enum "
10076                                                   "WHERE enumtypid = '%u'"
10077                                                   "ORDER BY enumsortorder",
10078                                                   tyinfo->dobj.catId.oid);
10079         else
10080                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10081                                                   "FROM pg_catalog.pg_enum "
10082                                                   "WHERE enumtypid = '%u'"
10083                                                   "ORDER BY oid",
10084                                                   tyinfo->dobj.catId.oid);
10085
10086         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10087
10088         num = PQntuples(res);
10089
10090         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10091         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10092
10093         /*
10094          * CASCADE shouldn't be required here as for normal types since the I/O
10095          * functions are generic and do not get dropped.
10096          */
10097         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10098
10099         if (dopt->binary_upgrade)
10100                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10101                                                                                                  tyinfo->dobj.catId.oid,
10102                                                                                                  false);
10103
10104         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10105                                           qualtypname);
10106
10107         if (!dopt->binary_upgrade)
10108         {
10109                 /* Labels with server-assigned oids */
10110                 for (i = 0; i < num; i++)
10111                 {
10112                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10113                         if (i > 0)
10114                                 appendPQExpBufferChar(q, ',');
10115                         appendPQExpBufferStr(q, "\n    ");
10116                         appendStringLiteralAH(q, label, fout);
10117                 }
10118         }
10119
10120         appendPQExpBufferStr(q, "\n);\n");
10121
10122         if (dopt->binary_upgrade)
10123         {
10124                 /* Labels with dump-assigned (preserved) oids */
10125                 for (i = 0; i < num; i++)
10126                 {
10127                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10128                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10129
10130                         if (i == 0)
10131                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10132                         appendPQExpBuffer(q,
10133                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10134                                                           enum_oid);
10135                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10136                         appendStringLiteralAH(q, label, fout);
10137                         appendPQExpBufferStr(q, ";\n\n");
10138                 }
10139         }
10140
10141         if (dopt->binary_upgrade)
10142                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10143                                                                                 "TYPE", qtypname,
10144                                                                                 tyinfo->dobj.namespace->dobj.name);
10145
10146         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10147                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10148                                          tyinfo->dobj.name,
10149                                          tyinfo->dobj.namespace->dobj.name,
10150                                          NULL,
10151                                          tyinfo->rolname, false,
10152                                          "TYPE", SECTION_PRE_DATA,
10153                                          q->data, delq->data, NULL,
10154                                          NULL, 0,
10155                                          NULL, NULL);
10156
10157         /* Dump Type Comments and Security Labels */
10158         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10159                 dumpComment(fout, "TYPE", qtypname,
10160                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10161                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10162
10163         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10164                 dumpSecLabel(fout, "TYPE", qtypname,
10165                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10166                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10167
10168         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10169                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10170                                 qtypname, NULL,
10171                                 tyinfo->dobj.namespace->dobj.name,
10172                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10173                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10174
10175         PQclear(res);
10176         destroyPQExpBuffer(q);
10177         destroyPQExpBuffer(delq);
10178         destroyPQExpBuffer(query);
10179         free(qtypname);
10180         free(qualtypname);
10181 }
10182
10183 /*
10184  * dumpRangeType
10185  *        writes out to fout the queries to recreate a user-defined range type
10186  */
10187 static void
10188 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10189 {
10190         DumpOptions *dopt = fout->dopt;
10191         PQExpBuffer q = createPQExpBuffer();
10192         PQExpBuffer delq = createPQExpBuffer();
10193         PQExpBuffer query = createPQExpBuffer();
10194         PGresult   *res;
10195         Oid                     collationOid;
10196         char       *qtypname;
10197         char       *qualtypname;
10198         char       *procname;
10199
10200         appendPQExpBuffer(query,
10201                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10202                                           "opc.opcname AS opcname, "
10203                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10204                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10205                                           "opc.opcdefault, "
10206                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10207                                           "     ELSE rngcollation END AS collation, "
10208                                           "rngcanonical, rngsubdiff "
10209                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10210                                           "     pg_catalog.pg_opclass opc "
10211                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10212                                           "rngtypid = '%u'",
10213                                           tyinfo->dobj.catId.oid);
10214
10215         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10216
10217         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10218         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10219
10220         /*
10221          * CASCADE shouldn't be required here as for normal types since the I/O
10222          * functions are generic and do not get dropped.
10223          */
10224         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10225
10226         if (dopt->binary_upgrade)
10227                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10228                                                                                                  tyinfo->dobj.catId.oid,
10229                                                                                                  false);
10230
10231         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10232                                           qualtypname);
10233
10234         appendPQExpBuffer(q, "\n    subtype = %s",
10235                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10236
10237         /* print subtype_opclass only if not default for subtype */
10238         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10239         {
10240                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10241                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10242
10243                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10244                                                   fmtId(nspname));
10245                 appendPQExpBufferStr(q, fmtId(opcname));
10246         }
10247
10248         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10249         if (OidIsValid(collationOid))
10250         {
10251                 CollInfo   *coll = findCollationByOid(collationOid);
10252
10253                 if (coll)
10254                         appendPQExpBuffer(q, ",\n    collation = %s",
10255                                                           fmtQualifiedDumpable(coll));
10256         }
10257
10258         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10259         if (strcmp(procname, "-") != 0)
10260                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10261
10262         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10263         if (strcmp(procname, "-") != 0)
10264                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10265
10266         appendPQExpBufferStr(q, "\n);\n");
10267
10268         if (dopt->binary_upgrade)
10269                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10270                                                                                 "TYPE", qtypname,
10271                                                                                 tyinfo->dobj.namespace->dobj.name);
10272
10273         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10274                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10275                                          tyinfo->dobj.name,
10276                                          tyinfo->dobj.namespace->dobj.name,
10277                                          NULL,
10278                                          tyinfo->rolname, false,
10279                                          "TYPE", SECTION_PRE_DATA,
10280                                          q->data, delq->data, NULL,
10281                                          NULL, 0,
10282                                          NULL, NULL);
10283
10284         /* Dump Type Comments and Security Labels */
10285         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10286                 dumpComment(fout, "TYPE", qtypname,
10287                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10288                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10289
10290         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10291                 dumpSecLabel(fout, "TYPE", qtypname,
10292                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10293                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10294
10295         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10296                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10297                                 qtypname, NULL,
10298                                 tyinfo->dobj.namespace->dobj.name,
10299                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10300                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10301
10302         PQclear(res);
10303         destroyPQExpBuffer(q);
10304         destroyPQExpBuffer(delq);
10305         destroyPQExpBuffer(query);
10306         free(qtypname);
10307         free(qualtypname);
10308 }
10309
10310 /*
10311  * dumpUndefinedType
10312  *        writes out to fout the queries to recreate a !typisdefined type
10313  *
10314  * This is a shell type, but we use different terminology to distinguish
10315  * this case from where we have to emit a shell type definition to break
10316  * circular dependencies.  An undefined type shouldn't ever have anything
10317  * depending on it.
10318  */
10319 static void
10320 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10321 {
10322         DumpOptions *dopt = fout->dopt;
10323         PQExpBuffer q = createPQExpBuffer();
10324         PQExpBuffer delq = createPQExpBuffer();
10325         char       *qtypname;
10326         char       *qualtypname;
10327
10328         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10329         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10330
10331         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10332
10333         if (dopt->binary_upgrade)
10334                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10335                                                                                                  tyinfo->dobj.catId.oid,
10336                                                                                                  false);
10337
10338         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10339                                           qualtypname);
10340
10341         if (dopt->binary_upgrade)
10342                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10343                                                                                 "TYPE", qtypname,
10344                                                                                 tyinfo->dobj.namespace->dobj.name);
10345
10346         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10347                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10348                                          tyinfo->dobj.name,
10349                                          tyinfo->dobj.namespace->dobj.name,
10350                                          NULL,
10351                                          tyinfo->rolname, false,
10352                                          "TYPE", SECTION_PRE_DATA,
10353                                          q->data, delq->data, NULL,
10354                                          NULL, 0,
10355                                          NULL, NULL);
10356
10357         /* Dump Type Comments and Security Labels */
10358         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10359                 dumpComment(fout, "TYPE", qtypname,
10360                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10361                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10362
10363         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10364                 dumpSecLabel(fout, "TYPE", qtypname,
10365                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10366                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10367
10368         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10369                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10370                                 qtypname, NULL,
10371                                 tyinfo->dobj.namespace->dobj.name,
10372                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10373                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10374
10375         destroyPQExpBuffer(q);
10376         destroyPQExpBuffer(delq);
10377         free(qtypname);
10378         free(qualtypname);
10379 }
10380
10381 /*
10382  * dumpBaseType
10383  *        writes out to fout the queries to recreate a user-defined base type
10384  */
10385 static void
10386 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10387 {
10388         DumpOptions *dopt = fout->dopt;
10389         PQExpBuffer q = createPQExpBuffer();
10390         PQExpBuffer delq = createPQExpBuffer();
10391         PQExpBuffer query = createPQExpBuffer();
10392         PGresult   *res;
10393         char       *qtypname;
10394         char       *qualtypname;
10395         char       *typlen;
10396         char       *typinput;
10397         char       *typoutput;
10398         char       *typreceive;
10399         char       *typsend;
10400         char       *typmodin;
10401         char       *typmodout;
10402         char       *typanalyze;
10403         Oid                     typreceiveoid;
10404         Oid                     typsendoid;
10405         Oid                     typmodinoid;
10406         Oid                     typmodoutoid;
10407         Oid                     typanalyzeoid;
10408         char       *typcategory;
10409         char       *typispreferred;
10410         char       *typdelim;
10411         char       *typbyval;
10412         char       *typalign;
10413         char       *typstorage;
10414         char       *typcollatable;
10415         char       *typdefault;
10416         bool            typdefault_is_literal = false;
10417
10418         /* Fetch type-specific details */
10419         if (fout->remoteVersion >= 90100)
10420         {
10421                 appendPQExpBuffer(query, "SELECT typlen, "
10422                                                   "typinput, typoutput, typreceive, typsend, "
10423                                                   "typmodin, typmodout, typanalyze, "
10424                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10425                                                   "typsend::pg_catalog.oid AS typsendoid, "
10426                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10427                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10428                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10429                                                   "typcategory, typispreferred, "
10430                                                   "typdelim, typbyval, typalign, typstorage, "
10431                                                   "(typcollation <> 0) AS typcollatable, "
10432                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10433                                                   "FROM pg_catalog.pg_type "
10434                                                   "WHERE oid = '%u'::pg_catalog.oid",
10435                                                   tyinfo->dobj.catId.oid);
10436         }
10437         else if (fout->remoteVersion >= 80400)
10438         {
10439                 appendPQExpBuffer(query, "SELECT typlen, "
10440                                                   "typinput, typoutput, typreceive, typsend, "
10441                                                   "typmodin, typmodout, typanalyze, "
10442                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10443                                                   "typsend::pg_catalog.oid AS typsendoid, "
10444                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10445                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10446                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10447                                                   "typcategory, typispreferred, "
10448                                                   "typdelim, typbyval, typalign, typstorage, "
10449                                                   "false AS typcollatable, "
10450                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10451                                                   "FROM pg_catalog.pg_type "
10452                                                   "WHERE oid = '%u'::pg_catalog.oid",
10453                                                   tyinfo->dobj.catId.oid);
10454         }
10455         else if (fout->remoteVersion >= 80300)
10456         {
10457                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10458                 appendPQExpBuffer(query, "SELECT typlen, "
10459                                                   "typinput, typoutput, typreceive, typsend, "
10460                                                   "typmodin, typmodout, typanalyze, "
10461                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10462                                                   "typsend::pg_catalog.oid AS typsendoid, "
10463                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10464                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10465                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10466                                                   "'U' AS typcategory, false AS typispreferred, "
10467                                                   "typdelim, typbyval, typalign, typstorage, "
10468                                                   "false AS typcollatable, "
10469                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10470                                                   "FROM pg_catalog.pg_type "
10471                                                   "WHERE oid = '%u'::pg_catalog.oid",
10472                                                   tyinfo->dobj.catId.oid);
10473         }
10474         else
10475         {
10476                 appendPQExpBuffer(query, "SELECT typlen, "
10477                                                   "typinput, typoutput, typreceive, typsend, "
10478                                                   "'-' AS typmodin, '-' AS typmodout, "
10479                                                   "typanalyze, "
10480                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10481                                                   "typsend::pg_catalog.oid AS typsendoid, "
10482                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10483                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10484                                                   "'U' AS typcategory, false AS typispreferred, "
10485                                                   "typdelim, typbyval, typalign, typstorage, "
10486                                                   "false AS typcollatable, "
10487                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10488                                                   "FROM pg_catalog.pg_type "
10489                                                   "WHERE oid = '%u'::pg_catalog.oid",
10490                                                   tyinfo->dobj.catId.oid);
10491         }
10492
10493         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10494
10495         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10496         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10497         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10498         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10499         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10500         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10501         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10502         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10503         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10504         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10505         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10506         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10507         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10508         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10509         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10510         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10511         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10512         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10513         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10514         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10515         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10516                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10517         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10518         {
10519                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10520                 typdefault_is_literal = true;   /* it needs quotes */
10521         }
10522         else
10523                 typdefault = NULL;
10524
10525         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10526         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10527
10528         /*
10529          * The reason we include CASCADE is that the circular dependency between
10530          * the type and its I/O functions makes it impossible to drop the type any
10531          * other way.
10532          */
10533         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10534
10535         /*
10536          * We might already have a shell type, but setting pg_type_oid is
10537          * harmless, and in any case we'd better set the array type OID.
10538          */
10539         if (dopt->binary_upgrade)
10540                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10541                                                                                                  tyinfo->dobj.catId.oid,
10542                                                                                                  false);
10543
10544         appendPQExpBuffer(q,
10545                                           "CREATE TYPE %s (\n"
10546                                           "    INTERNALLENGTH = %s",
10547                                           qualtypname,
10548                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10549
10550         /* regproc result is sufficiently quoted already */
10551         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10552         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10553         if (OidIsValid(typreceiveoid))
10554                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10555         if (OidIsValid(typsendoid))
10556                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10557         if (OidIsValid(typmodinoid))
10558                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10559         if (OidIsValid(typmodoutoid))
10560                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10561         if (OidIsValid(typanalyzeoid))
10562                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10563
10564         if (strcmp(typcollatable, "t") == 0)
10565                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10566
10567         if (typdefault != NULL)
10568         {
10569                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10570                 if (typdefault_is_literal)
10571                         appendStringLiteralAH(q, typdefault, fout);
10572                 else
10573                         appendPQExpBufferStr(q, typdefault);
10574         }
10575
10576         if (OidIsValid(tyinfo->typelem))
10577         {
10578                 char       *elemType;
10579
10580                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10581                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10582                 free(elemType);
10583         }
10584
10585         if (strcmp(typcategory, "U") != 0)
10586         {
10587                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10588                 appendStringLiteralAH(q, typcategory, fout);
10589         }
10590
10591         if (strcmp(typispreferred, "t") == 0)
10592                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10593
10594         if (typdelim && strcmp(typdelim, ",") != 0)
10595         {
10596                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10597                 appendStringLiteralAH(q, typdelim, fout);
10598         }
10599
10600         if (strcmp(typalign, "c") == 0)
10601                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10602         else if (strcmp(typalign, "s") == 0)
10603                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10604         else if (strcmp(typalign, "i") == 0)
10605                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10606         else if (strcmp(typalign, "d") == 0)
10607                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10608
10609         if (strcmp(typstorage, "p") == 0)
10610                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10611         else if (strcmp(typstorage, "e") == 0)
10612                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10613         else if (strcmp(typstorage, "x") == 0)
10614                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10615         else if (strcmp(typstorage, "m") == 0)
10616                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10617
10618         if (strcmp(typbyval, "t") == 0)
10619                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10620
10621         appendPQExpBufferStr(q, "\n);\n");
10622
10623         if (dopt->binary_upgrade)
10624                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10625                                                                                 "TYPE", qtypname,
10626                                                                                 tyinfo->dobj.namespace->dobj.name);
10627
10628         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10629                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10630                                          tyinfo->dobj.name,
10631                                          tyinfo->dobj.namespace->dobj.name,
10632                                          NULL,
10633                                          tyinfo->rolname, false,
10634                                          "TYPE", SECTION_PRE_DATA,
10635                                          q->data, delq->data, NULL,
10636                                          NULL, 0,
10637                                          NULL, NULL);
10638
10639         /* Dump Type Comments and Security Labels */
10640         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10641                 dumpComment(fout, "TYPE", qtypname,
10642                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10643                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10644
10645         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10646                 dumpSecLabel(fout, "TYPE", qtypname,
10647                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10648                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10649
10650         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10651                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10652                                 qtypname, NULL,
10653                                 tyinfo->dobj.namespace->dobj.name,
10654                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10655                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10656
10657         PQclear(res);
10658         destroyPQExpBuffer(q);
10659         destroyPQExpBuffer(delq);
10660         destroyPQExpBuffer(query);
10661         free(qtypname);
10662         free(qualtypname);
10663 }
10664
10665 /*
10666  * dumpDomain
10667  *        writes out to fout the queries to recreate a user-defined domain
10668  */
10669 static void
10670 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10671 {
10672         DumpOptions *dopt = fout->dopt;
10673         PQExpBuffer q = createPQExpBuffer();
10674         PQExpBuffer delq = createPQExpBuffer();
10675         PQExpBuffer query = createPQExpBuffer();
10676         PGresult   *res;
10677         int                     i;
10678         char       *qtypname;
10679         char       *qualtypname;
10680         char       *typnotnull;
10681         char       *typdefn;
10682         char       *typdefault;
10683         Oid                     typcollation;
10684         bool            typdefault_is_literal = false;
10685
10686         /* Fetch domain specific details */
10687         if (fout->remoteVersion >= 90100)
10688         {
10689                 /* typcollation is new in 9.1 */
10690                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10691                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10692                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10693                                                   "t.typdefault, "
10694                                                   "CASE WHEN t.typcollation <> u.typcollation "
10695                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10696                                                   "FROM pg_catalog.pg_type t "
10697                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10698                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10699                                                   tyinfo->dobj.catId.oid);
10700         }
10701         else
10702         {
10703                 appendPQExpBuffer(query, "SELECT typnotnull, "
10704                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10705                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10706                                                   "typdefault, 0 AS typcollation "
10707                                                   "FROM pg_catalog.pg_type "
10708                                                   "WHERE oid = '%u'::pg_catalog.oid",
10709                                                   tyinfo->dobj.catId.oid);
10710         }
10711
10712         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10713
10714         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10715         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10716         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10717                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10718         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10719         {
10720                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10721                 typdefault_is_literal = true;   /* it needs quotes */
10722         }
10723         else
10724                 typdefault = NULL;
10725         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10726
10727         if (dopt->binary_upgrade)
10728                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10729                                                                                                  tyinfo->dobj.catId.oid,
10730                                                                                                  true); /* force array type */
10731
10732         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10733         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10734
10735         appendPQExpBuffer(q,
10736                                           "CREATE DOMAIN %s AS %s",
10737                                           qualtypname,
10738                                           typdefn);
10739
10740         /* Print collation only if different from base type's collation */
10741         if (OidIsValid(typcollation))
10742         {
10743                 CollInfo   *coll;
10744
10745                 coll = findCollationByOid(typcollation);
10746                 if (coll)
10747                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10748         }
10749
10750         if (typnotnull[0] == 't')
10751                 appendPQExpBufferStr(q, " NOT NULL");
10752
10753         if (typdefault != NULL)
10754         {
10755                 appendPQExpBufferStr(q, " DEFAULT ");
10756                 if (typdefault_is_literal)
10757                         appendStringLiteralAH(q, typdefault, fout);
10758                 else
10759                         appendPQExpBufferStr(q, typdefault);
10760         }
10761
10762         PQclear(res);
10763
10764         /*
10765          * Add any CHECK constraints for the domain
10766          */
10767         for (i = 0; i < tyinfo->nDomChecks; i++)
10768         {
10769                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10770
10771                 if (!domcheck->separate)
10772                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10773                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10774         }
10775
10776         appendPQExpBufferStr(q, ";\n");
10777
10778         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10779
10780         if (dopt->binary_upgrade)
10781                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10782                                                                                 "DOMAIN", qtypname,
10783                                                                                 tyinfo->dobj.namespace->dobj.name);
10784
10785         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10786                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10787                                          tyinfo->dobj.name,
10788                                          tyinfo->dobj.namespace->dobj.name,
10789                                          NULL,
10790                                          tyinfo->rolname, false,
10791                                          "DOMAIN", SECTION_PRE_DATA,
10792                                          q->data, delq->data, NULL,
10793                                          NULL, 0,
10794                                          NULL, NULL);
10795
10796         /* Dump Domain Comments and Security Labels */
10797         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10798                 dumpComment(fout, "DOMAIN", qtypname,
10799                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10800                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10801
10802         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10803                 dumpSecLabel(fout, "DOMAIN", qtypname,
10804                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10805                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10806
10807         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10808                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10809                                 qtypname, NULL,
10810                                 tyinfo->dobj.namespace->dobj.name,
10811                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10812                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10813
10814         /* Dump any per-constraint comments */
10815         for (i = 0; i < tyinfo->nDomChecks; i++)
10816         {
10817                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10818                 PQExpBuffer conprefix = createPQExpBuffer();
10819
10820                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10821                                                   fmtId(domcheck->dobj.name));
10822
10823                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10824                         dumpComment(fout, conprefix->data, qtypname,
10825                                                 tyinfo->dobj.namespace->dobj.name,
10826                                                 tyinfo->rolname,
10827                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10828
10829                 destroyPQExpBuffer(conprefix);
10830         }
10831
10832         destroyPQExpBuffer(q);
10833         destroyPQExpBuffer(delq);
10834         destroyPQExpBuffer(query);
10835         free(qtypname);
10836         free(qualtypname);
10837 }
10838
10839 /*
10840  * dumpCompositeType
10841  *        writes out to fout the queries to recreate a user-defined stand-alone
10842  *        composite type
10843  */
10844 static void
10845 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10846 {
10847         DumpOptions *dopt = fout->dopt;
10848         PQExpBuffer q = createPQExpBuffer();
10849         PQExpBuffer dropped = createPQExpBuffer();
10850         PQExpBuffer delq = createPQExpBuffer();
10851         PQExpBuffer query = createPQExpBuffer();
10852         PGresult   *res;
10853         char       *qtypname;
10854         char       *qualtypname;
10855         int                     ntups;
10856         int                     i_attname;
10857         int                     i_atttypdefn;
10858         int                     i_attlen;
10859         int                     i_attalign;
10860         int                     i_attisdropped;
10861         int                     i_attcollation;
10862         int                     i;
10863         int                     actual_atts;
10864
10865         /* Fetch type specific details */
10866         if (fout->remoteVersion >= 90100)
10867         {
10868                 /*
10869                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10870                  * clauses for attributes whose collation is different from their
10871                  * type's default, we use a CASE here to suppress uninteresting
10872                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10873                  * collation does not matter for those.
10874                  */
10875                 appendPQExpBuffer(query, "SELECT a.attname, "
10876                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10877                                                   "a.attlen, a.attalign, a.attisdropped, "
10878                                                   "CASE WHEN a.attcollation <> at.typcollation "
10879                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10880                                                   "FROM pg_catalog.pg_type ct "
10881                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10882                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10883                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10884                                                   "ORDER BY a.attnum ",
10885                                                   tyinfo->dobj.catId.oid);
10886         }
10887         else
10888         {
10889                 /*
10890                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10891                  * should always be false.
10892                  */
10893                 appendPQExpBuffer(query, "SELECT a.attname, "
10894                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10895                                                   "a.attlen, a.attalign, a.attisdropped, "
10896                                                   "0 AS attcollation "
10897                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10898                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10899                                                   "AND a.attrelid = ct.typrelid "
10900                                                   "ORDER BY a.attnum ",
10901                                                   tyinfo->dobj.catId.oid);
10902         }
10903
10904         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10905
10906         ntups = PQntuples(res);
10907
10908         i_attname = PQfnumber(res, "attname");
10909         i_atttypdefn = PQfnumber(res, "atttypdefn");
10910         i_attlen = PQfnumber(res, "attlen");
10911         i_attalign = PQfnumber(res, "attalign");
10912         i_attisdropped = PQfnumber(res, "attisdropped");
10913         i_attcollation = PQfnumber(res, "attcollation");
10914
10915         if (dopt->binary_upgrade)
10916         {
10917                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10918                                                                                                  tyinfo->dobj.catId.oid,
10919                                                                                                  false);
10920                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10921         }
10922
10923         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10924         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10925
10926         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10927                                           qualtypname);
10928
10929         actual_atts = 0;
10930         for (i = 0; i < ntups; i++)
10931         {
10932                 char       *attname;
10933                 char       *atttypdefn;
10934                 char       *attlen;
10935                 char       *attalign;
10936                 bool            attisdropped;
10937                 Oid                     attcollation;
10938
10939                 attname = PQgetvalue(res, i, i_attname);
10940                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10941                 attlen = PQgetvalue(res, i, i_attlen);
10942                 attalign = PQgetvalue(res, i, i_attalign);
10943                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10944                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10945
10946                 if (attisdropped && !dopt->binary_upgrade)
10947                         continue;
10948
10949                 /* Format properly if not first attr */
10950                 if (actual_atts++ > 0)
10951                         appendPQExpBufferChar(q, ',');
10952                 appendPQExpBufferStr(q, "\n\t");
10953
10954                 if (!attisdropped)
10955                 {
10956                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10957
10958                         /* Add collation if not default for the column type */
10959                         if (OidIsValid(attcollation))
10960                         {
10961                                 CollInfo   *coll;
10962
10963                                 coll = findCollationByOid(attcollation);
10964                                 if (coll)
10965                                         appendPQExpBuffer(q, " COLLATE %s",
10966                                                                           fmtQualifiedDumpable(coll));
10967                         }
10968                 }
10969                 else
10970                 {
10971                         /*
10972                          * This is a dropped attribute and we're in binary_upgrade mode.
10973                          * Insert a placeholder for it in the CREATE TYPE command, and set
10974                          * length and alignment with direct UPDATE to the catalogs
10975                          * afterwards. See similar code in dumpTableSchema().
10976                          */
10977                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10978
10979                         /* stash separately for insertion after the CREATE TYPE */
10980                         appendPQExpBufferStr(dropped,
10981                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
10982                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10983                                                           "SET attlen = %s, "
10984                                                           "attalign = '%s', attbyval = false\n"
10985                                                           "WHERE attname = ", attlen, attalign);
10986                         appendStringLiteralAH(dropped, attname, fout);
10987                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
10988                         appendStringLiteralAH(dropped, qualtypname, fout);
10989                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10990
10991                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10992                                                           qualtypname);
10993                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10994                                                           fmtId(attname));
10995                 }
10996         }
10997         appendPQExpBufferStr(q, "\n);\n");
10998         appendPQExpBufferStr(q, dropped->data);
10999
11000         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11001
11002         if (dopt->binary_upgrade)
11003                 binary_upgrade_extension_member(q, &tyinfo->dobj,
11004                                                                                 "TYPE", qtypname,
11005                                                                                 tyinfo->dobj.namespace->dobj.name);
11006
11007         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11008                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11009                                          tyinfo->dobj.name,
11010                                          tyinfo->dobj.namespace->dobj.name,
11011                                          NULL,
11012                                          tyinfo->rolname, false,
11013                                          "TYPE", SECTION_PRE_DATA,
11014                                          q->data, delq->data, NULL,
11015                                          NULL, 0,
11016                                          NULL, NULL);
11017
11018
11019         /* Dump Type Comments and Security Labels */
11020         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11021                 dumpComment(fout, "TYPE", qtypname,
11022                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11023                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11024
11025         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11026                 dumpSecLabel(fout, "TYPE", qtypname,
11027                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11028                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11029
11030         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11031                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11032                                 qtypname, NULL,
11033                                 tyinfo->dobj.namespace->dobj.name,
11034                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11035                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11036
11037         PQclear(res);
11038         destroyPQExpBuffer(q);
11039         destroyPQExpBuffer(dropped);
11040         destroyPQExpBuffer(delq);
11041         destroyPQExpBuffer(query);
11042         free(qtypname);
11043         free(qualtypname);
11044
11045         /* Dump any per-column comments */
11046         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11047                 dumpCompositeTypeColComments(fout, tyinfo);
11048 }
11049
11050 /*
11051  * dumpCompositeTypeColComments
11052  *        writes out to fout the queries to recreate comments on the columns of
11053  *        a user-defined stand-alone composite type
11054  */
11055 static void
11056 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11057 {
11058         CommentItem *comments;
11059         int                     ncomments;
11060         PGresult   *res;
11061         PQExpBuffer query;
11062         PQExpBuffer target;
11063         Oid                     pgClassOid;
11064         int                     i;
11065         int                     ntups;
11066         int                     i_attname;
11067         int                     i_attnum;
11068
11069         /* do nothing, if --no-comments is supplied */
11070         if (fout->dopt->no_comments)
11071                 return;
11072
11073         query = createPQExpBuffer();
11074
11075         appendPQExpBuffer(query,
11076                                           "SELECT c.tableoid, a.attname, a.attnum "
11077                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11078                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11079                                           "  AND NOT a.attisdropped "
11080                                           "ORDER BY a.attnum ",
11081                                           tyinfo->typrelid);
11082
11083         /* Fetch column attnames */
11084         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11085
11086         ntups = PQntuples(res);
11087         if (ntups < 1)
11088         {
11089                 PQclear(res);
11090                 destroyPQExpBuffer(query);
11091                 return;
11092         }
11093
11094         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11095
11096         /* Search for comments associated with type's pg_class OID */
11097         ncomments = findComments(fout,
11098                                                          pgClassOid,
11099                                                          tyinfo->typrelid,
11100                                                          &comments);
11101
11102         /* If no comments exist, we're done */
11103         if (ncomments <= 0)
11104         {
11105                 PQclear(res);
11106                 destroyPQExpBuffer(query);
11107                 return;
11108         }
11109
11110         /* Build COMMENT ON statements */
11111         target = createPQExpBuffer();
11112
11113         i_attnum = PQfnumber(res, "attnum");
11114         i_attname = PQfnumber(res, "attname");
11115         while (ncomments > 0)
11116         {
11117                 const char *attname;
11118
11119                 attname = NULL;
11120                 for (i = 0; i < ntups; i++)
11121                 {
11122                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11123                         {
11124                                 attname = PQgetvalue(res, i, i_attname);
11125                                 break;
11126                         }
11127                 }
11128                 if (attname)                    /* just in case we don't find it */
11129                 {
11130                         const char *descr = comments->descr;
11131
11132                         resetPQExpBuffer(target);
11133                         appendPQExpBuffer(target, "COLUMN %s.",
11134                                                           fmtId(tyinfo->dobj.name));
11135                         appendPQExpBufferStr(target, fmtId(attname));
11136
11137                         resetPQExpBuffer(query);
11138                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11139                                                           fmtQualifiedDumpable(tyinfo));
11140                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11141                         appendStringLiteralAH(query, descr, fout);
11142                         appendPQExpBufferStr(query, ";\n");
11143
11144                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11145                                                  target->data,
11146                                                  tyinfo->dobj.namespace->dobj.name,
11147                                                  NULL, tyinfo->rolname,
11148                                                  false, "COMMENT", SECTION_NONE,
11149                                                  query->data, "", NULL,
11150                                                  &(tyinfo->dobj.dumpId), 1,
11151                                                  NULL, NULL);
11152                 }
11153
11154                 comments++;
11155                 ncomments--;
11156         }
11157
11158         PQclear(res);
11159         destroyPQExpBuffer(query);
11160         destroyPQExpBuffer(target);
11161 }
11162
11163 /*
11164  * dumpShellType
11165  *        writes out to fout the queries to create a shell type
11166  *
11167  * We dump a shell definition in advance of the I/O functions for the type.
11168  */
11169 static void
11170 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11171 {
11172         DumpOptions *dopt = fout->dopt;
11173         PQExpBuffer q;
11174
11175         /* Skip if not to be dumped */
11176         if (!stinfo->dobj.dump || dopt->dataOnly)
11177                 return;
11178
11179         q = createPQExpBuffer();
11180
11181         /*
11182          * Note the lack of a DROP command for the shell type; any required DROP
11183          * is driven off the base type entry, instead.  This interacts with
11184          * _printTocEntry()'s use of the presence of a DROP command to decide
11185          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11186          * the shell type's owner immediately on creation; that should happen only
11187          * after it's filled in, otherwise the backend complains.
11188          */
11189
11190         if (dopt->binary_upgrade)
11191                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11192                                                                                                  stinfo->baseType->dobj.catId.oid,
11193                                                                                                  false);
11194
11195         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11196                                           fmtQualifiedDumpable(stinfo));
11197
11198         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11199                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11200                                          stinfo->dobj.name,
11201                                          stinfo->dobj.namespace->dobj.name,
11202                                          NULL,
11203                                          stinfo->baseType->rolname, false,
11204                                          "SHELL TYPE", SECTION_PRE_DATA,
11205                                          q->data, "", NULL,
11206                                          NULL, 0,
11207                                          NULL, NULL);
11208
11209         destroyPQExpBuffer(q);
11210 }
11211
11212 /*
11213  * dumpProcLang
11214  *                writes out to fout the queries to recreate a user-defined
11215  *                procedural language
11216  */
11217 static void
11218 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11219 {
11220         DumpOptions *dopt = fout->dopt;
11221         PQExpBuffer defqry;
11222         PQExpBuffer delqry;
11223         bool            useParams;
11224         char       *qlanname;
11225         FuncInfo   *funcInfo;
11226         FuncInfo   *inlineInfo = NULL;
11227         FuncInfo   *validatorInfo = NULL;
11228
11229         /* Skip if not to be dumped */
11230         if (!plang->dobj.dump || dopt->dataOnly)
11231                 return;
11232
11233         /*
11234          * Try to find the support function(s).  It is not an error if we don't
11235          * find them --- if the functions are in the pg_catalog schema, as is
11236          * standard in 8.1 and up, then we won't have loaded them. (In this case
11237          * we will emit a parameterless CREATE LANGUAGE command, which will
11238          * require PL template knowledge in the backend to reload.)
11239          */
11240
11241         funcInfo = findFuncByOid(plang->lanplcallfoid);
11242         if (funcInfo != NULL && !funcInfo->dobj.dump)
11243                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11244
11245         if (OidIsValid(plang->laninline))
11246         {
11247                 inlineInfo = findFuncByOid(plang->laninline);
11248                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11249                         inlineInfo = NULL;
11250         }
11251
11252         if (OidIsValid(plang->lanvalidator))
11253         {
11254                 validatorInfo = findFuncByOid(plang->lanvalidator);
11255                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11256                         validatorInfo = NULL;
11257         }
11258
11259         /*
11260          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11261          * with parameters.  Otherwise, we'll write a parameterless command, which
11262          * will rely on data from pg_pltemplate.
11263          */
11264         useParams = (funcInfo != NULL &&
11265                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11266                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11267
11268         defqry = createPQExpBuffer();
11269         delqry = createPQExpBuffer();
11270
11271         qlanname = pg_strdup(fmtId(plang->dobj.name));
11272
11273         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11274                                           qlanname);
11275
11276         if (useParams)
11277         {
11278                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11279                                                   plang->lanpltrusted ? "TRUSTED " : "",
11280                                                   qlanname);
11281                 appendPQExpBuffer(defqry, " HANDLER %s",
11282                                                   fmtQualifiedDumpable(funcInfo));
11283                 if (OidIsValid(plang->laninline))
11284                         appendPQExpBuffer(defqry, " INLINE %s",
11285                                                           fmtQualifiedDumpable(inlineInfo));
11286                 if (OidIsValid(plang->lanvalidator))
11287                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11288                                                           fmtQualifiedDumpable(validatorInfo));
11289         }
11290         else
11291         {
11292                 /*
11293                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11294                  * command will not fail if the language is preinstalled in the target
11295                  * database.  We restrict the use of REPLACE to this case so as to
11296                  * eliminate the risk of replacing a language with incompatible
11297                  * parameter settings: this command will only succeed at all if there
11298                  * is a pg_pltemplate entry, and if there is one, the existing entry
11299                  * must match it too.
11300                  */
11301                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11302                                                   qlanname);
11303         }
11304         appendPQExpBufferStr(defqry, ";\n");
11305
11306         if (dopt->binary_upgrade)
11307                 binary_upgrade_extension_member(defqry, &plang->dobj,
11308                                                                                 "LANGUAGE", qlanname, NULL);
11309
11310         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11311                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11312                                          plang->dobj.name,
11313                                          NULL, NULL, plang->lanowner,
11314                                          false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11315                                          defqry->data, delqry->data, NULL,
11316                                          NULL, 0,
11317                                          NULL, NULL);
11318
11319         /* Dump Proc Lang Comments and Security Labels */
11320         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11321                 dumpComment(fout, "LANGUAGE", qlanname,
11322                                         NULL, plang->lanowner,
11323                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11324
11325         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11326                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11327                                          NULL, plang->lanowner,
11328                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11329
11330         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11331                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11332                                 qlanname, NULL, NULL,
11333                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11334                                 plang->initlanacl, plang->initrlanacl);
11335
11336         free(qlanname);
11337
11338         destroyPQExpBuffer(defqry);
11339         destroyPQExpBuffer(delqry);
11340 }
11341
11342 /*
11343  * format_function_arguments: generate function name and argument list
11344  *
11345  * This is used when we can rely on pg_get_function_arguments to format
11346  * the argument list.  Note, however, that pg_get_function_arguments
11347  * does not special-case zero-argument aggregates.
11348  */
11349 static char *
11350 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11351 {
11352         PQExpBufferData fn;
11353
11354         initPQExpBuffer(&fn);
11355         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11356         if (is_agg && finfo->nargs == 0)
11357                 appendPQExpBufferStr(&fn, "(*)");
11358         else
11359                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11360         return fn.data;
11361 }
11362
11363 /*
11364  * format_function_arguments_old: generate function name and argument list
11365  *
11366  * The argument type names are qualified if needed.  The function name
11367  * is never qualified.
11368  *
11369  * This is used only with pre-8.4 servers, so we aren't expecting to see
11370  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11371  *
11372  * Any or all of allargtypes, argmodes, argnames may be NULL.
11373  */
11374 static char *
11375 format_function_arguments_old(Archive *fout,
11376                                                           FuncInfo *finfo, int nallargs,
11377                                                           char **allargtypes,
11378                                                           char **argmodes,
11379                                                           char **argnames)
11380 {
11381         PQExpBufferData fn;
11382         int                     j;
11383
11384         initPQExpBuffer(&fn);
11385         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11386         for (j = 0; j < nallargs; j++)
11387         {
11388                 Oid                     typid;
11389                 char       *typname;
11390                 const char *argmode;
11391                 const char *argname;
11392
11393                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11394                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11395
11396                 if (argmodes)
11397                 {
11398                         switch (argmodes[j][0])
11399                         {
11400                                 case PROARGMODE_IN:
11401                                         argmode = "";
11402                                         break;
11403                                 case PROARGMODE_OUT:
11404                                         argmode = "OUT ";
11405                                         break;
11406                                 case PROARGMODE_INOUT:
11407                                         argmode = "INOUT ";
11408                                         break;
11409                                 default:
11410                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11411                                         argmode = "";
11412                                         break;
11413                         }
11414                 }
11415                 else
11416                         argmode = "";
11417
11418                 argname = argnames ? argnames[j] : (char *) NULL;
11419                 if (argname && argname[0] == '\0')
11420                         argname = NULL;
11421
11422                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11423                                                   (j > 0) ? ", " : "",
11424                                                   argmode,
11425                                                   argname ? fmtId(argname) : "",
11426                                                   argname ? " " : "",
11427                                                   typname);
11428                 free(typname);
11429         }
11430         appendPQExpBufferChar(&fn, ')');
11431         return fn.data;
11432 }
11433
11434 /*
11435  * format_function_signature: generate function name and argument list
11436  *
11437  * This is like format_function_arguments_old except that only a minimal
11438  * list of input argument types is generated; this is sufficient to
11439  * reference the function, but not to define it.
11440  *
11441  * If honor_quotes is false then the function name is never quoted.
11442  * This is appropriate for use in TOC tags, but not in SQL commands.
11443  */
11444 static char *
11445 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11446 {
11447         PQExpBufferData fn;
11448         int                     j;
11449
11450         initPQExpBuffer(&fn);
11451         if (honor_quotes)
11452                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11453         else
11454                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11455         for (j = 0; j < finfo->nargs; j++)
11456         {
11457                 char       *typname;
11458
11459                 if (j > 0)
11460                         appendPQExpBufferStr(&fn, ", ");
11461
11462                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11463                                                                            zeroAsOpaque);
11464                 appendPQExpBufferStr(&fn, typname);
11465                 free(typname);
11466         }
11467         appendPQExpBufferChar(&fn, ')');
11468         return fn.data;
11469 }
11470
11471
11472 /*
11473  * dumpFunc:
11474  *        dump out one function
11475  */
11476 static void
11477 dumpFunc(Archive *fout, FuncInfo *finfo)
11478 {
11479         DumpOptions *dopt = fout->dopt;
11480         PQExpBuffer query;
11481         PQExpBuffer q;
11482         PQExpBuffer delqry;
11483         PQExpBuffer asPart;
11484         PGresult   *res;
11485         char       *funcsig;            /* identity signature */
11486         char       *funcfullsig = NULL; /* full signature */
11487         char       *funcsig_tag;
11488         char       *proretset;
11489         char       *prosrc;
11490         char       *probin;
11491         char       *funcargs;
11492         char       *funciargs;
11493         char       *funcresult;
11494         char       *proallargtypes;
11495         char       *proargmodes;
11496         char       *proargnames;
11497         char       *protrftypes;
11498         char       *prokind;
11499         char       *provolatile;
11500         char       *proisstrict;
11501         char       *prosecdef;
11502         char       *proleakproof;
11503         char       *proconfig;
11504         char       *procost;
11505         char       *prorows;
11506         char       *proparallel;
11507         char       *lanname;
11508         char       *rettypename;
11509         int                     nallargs;
11510         char      **allargtypes = NULL;
11511         char      **argmodes = NULL;
11512         char      **argnames = NULL;
11513         char      **configitems = NULL;
11514         int                     nconfigitems = 0;
11515         const char *keyword;
11516         int                     i;
11517
11518         /* Skip if not to be dumped */
11519         if (!finfo->dobj.dump || dopt->dataOnly)
11520                 return;
11521
11522         query = createPQExpBuffer();
11523         q = createPQExpBuffer();
11524         delqry = createPQExpBuffer();
11525         asPart = createPQExpBuffer();
11526
11527         /* Fetch function-specific details */
11528         if (fout->remoteVersion >= 110000)
11529         {
11530                 /*
11531                  * prokind was added in 11
11532                  */
11533                 appendPQExpBuffer(query,
11534                                                   "SELECT proretset, prosrc, probin, "
11535                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11536                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11537                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11538                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11539                                                   "prokind, provolatile, proisstrict, prosecdef, "
11540                                                   "proleakproof, proconfig, procost, prorows, "
11541                                                   "proparallel, "
11542                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11543                                                   "FROM pg_catalog.pg_proc "
11544                                                   "WHERE oid = '%u'::pg_catalog.oid",
11545                                                   finfo->dobj.catId.oid);
11546         }
11547         else if (fout->remoteVersion >= 90600)
11548         {
11549                 /*
11550                  * proparallel was added in 9.6
11551                  */
11552                 appendPQExpBuffer(query,
11553                                                   "SELECT proretset, prosrc, probin, "
11554                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11555                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11556                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11557                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11558                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11559                                                   "provolatile, proisstrict, prosecdef, "
11560                                                   "proleakproof, proconfig, procost, prorows, "
11561                                                   "proparallel, "
11562                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11563                                                   "FROM pg_catalog.pg_proc "
11564                                                   "WHERE oid = '%u'::pg_catalog.oid",
11565                                                   finfo->dobj.catId.oid);
11566         }
11567         else if (fout->remoteVersion >= 90500)
11568         {
11569                 /*
11570                  * protrftypes was added in 9.5
11571                  */
11572                 appendPQExpBuffer(query,
11573                                                   "SELECT proretset, prosrc, probin, "
11574                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11575                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11576                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11577                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11578                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11579                                                   "provolatile, proisstrict, prosecdef, "
11580                                                   "proleakproof, proconfig, procost, prorows, "
11581                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11582                                                   "FROM pg_catalog.pg_proc "
11583                                                   "WHERE oid = '%u'::pg_catalog.oid",
11584                                                   finfo->dobj.catId.oid);
11585         }
11586         else if (fout->remoteVersion >= 90200)
11587         {
11588                 /*
11589                  * proleakproof was added in 9.2
11590                  */
11591                 appendPQExpBuffer(query,
11592                                                   "SELECT proretset, prosrc, probin, "
11593                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11594                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11595                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11596                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11597                                                   "provolatile, proisstrict, prosecdef, "
11598                                                   "proleakproof, proconfig, procost, prorows, "
11599                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11600                                                   "FROM pg_catalog.pg_proc "
11601                                                   "WHERE oid = '%u'::pg_catalog.oid",
11602                                                   finfo->dobj.catId.oid);
11603         }
11604         else if (fout->remoteVersion >= 80400)
11605         {
11606                 /*
11607                  * In 8.4 and up we rely on pg_get_function_arguments and
11608                  * pg_get_function_result instead of examining proallargtypes etc.
11609                  */
11610                 appendPQExpBuffer(query,
11611                                                   "SELECT proretset, prosrc, probin, "
11612                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11613                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11614                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11615                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11616                                                   "provolatile, proisstrict, prosecdef, "
11617                                                   "false AS proleakproof, "
11618                                                   " proconfig, procost, prorows, "
11619                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11620                                                   "FROM pg_catalog.pg_proc "
11621                                                   "WHERE oid = '%u'::pg_catalog.oid",
11622                                                   finfo->dobj.catId.oid);
11623         }
11624         else if (fout->remoteVersion >= 80300)
11625         {
11626                 appendPQExpBuffer(query,
11627                                                   "SELECT proretset, prosrc, probin, "
11628                                                   "proallargtypes, proargmodes, proargnames, "
11629                                                   "'f' AS prokind, "
11630                                                   "provolatile, proisstrict, prosecdef, "
11631                                                   "false AS proleakproof, "
11632                                                   "proconfig, procost, prorows, "
11633                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11634                                                   "FROM pg_catalog.pg_proc "
11635                                                   "WHERE oid = '%u'::pg_catalog.oid",
11636                                                   finfo->dobj.catId.oid);
11637         }
11638         else if (fout->remoteVersion >= 80100)
11639         {
11640                 appendPQExpBuffer(query,
11641                                                   "SELECT proretset, prosrc, probin, "
11642                                                   "proallargtypes, proargmodes, proargnames, "
11643                                                   "'f' AS prokind, "
11644                                                   "provolatile, proisstrict, prosecdef, "
11645                                                   "false AS proleakproof, "
11646                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11647                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11648                                                   "FROM pg_catalog.pg_proc "
11649                                                   "WHERE oid = '%u'::pg_catalog.oid",
11650                                                   finfo->dobj.catId.oid);
11651         }
11652         else
11653         {
11654                 appendPQExpBuffer(query,
11655                                                   "SELECT proretset, prosrc, probin, "
11656                                                   "null AS proallargtypes, "
11657                                                   "null AS proargmodes, "
11658                                                   "proargnames, "
11659                                                   "'f' AS prokind, "
11660                                                   "provolatile, proisstrict, prosecdef, "
11661                                                   "false AS proleakproof, "
11662                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11663                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11664                                                   "FROM pg_catalog.pg_proc "
11665                                                   "WHERE oid = '%u'::pg_catalog.oid",
11666                                                   finfo->dobj.catId.oid);
11667         }
11668
11669         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11670
11671         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11672         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11673         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11674         if (fout->remoteVersion >= 80400)
11675         {
11676                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11677                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11678                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11679                 proallargtypes = proargmodes = proargnames = NULL;
11680         }
11681         else
11682         {
11683                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11684                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11685                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11686                 funcargs = funciargs = funcresult = NULL;
11687         }
11688         if (PQfnumber(res, "protrftypes") != -1)
11689                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11690         else
11691                 protrftypes = NULL;
11692         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11693         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11694         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11695         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11696         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11697         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11698         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11699         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11700
11701         if (PQfnumber(res, "proparallel") != -1)
11702                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11703         else
11704                 proparallel = NULL;
11705
11706         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11707
11708         /*
11709          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11710          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11711          * versions would set it to "-".  There are no known cases in which prosrc
11712          * is unused, so the tests below for "-" are probably useless.
11713          */
11714         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11715         {
11716                 appendPQExpBufferStr(asPart, "AS ");
11717                 appendStringLiteralAH(asPart, probin, fout);
11718                 if (strcmp(prosrc, "-") != 0)
11719                 {
11720                         appendPQExpBufferStr(asPart, ", ");
11721
11722                         /*
11723                          * where we have bin, use dollar quoting if allowed and src
11724                          * contains quote or backslash; else use regular quoting.
11725                          */
11726                         if (dopt->disable_dollar_quoting ||
11727                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11728                                 appendStringLiteralAH(asPart, prosrc, fout);
11729                         else
11730                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11731                 }
11732         }
11733         else
11734         {
11735                 if (strcmp(prosrc, "-") != 0)
11736                 {
11737                         appendPQExpBufferStr(asPart, "AS ");
11738                         /* with no bin, dollar quote src unconditionally if allowed */
11739                         if (dopt->disable_dollar_quoting)
11740                                 appendStringLiteralAH(asPart, prosrc, fout);
11741                         else
11742                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11743                 }
11744         }
11745
11746         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11747
11748         if (proallargtypes && *proallargtypes)
11749         {
11750                 int                     nitems = 0;
11751
11752                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11753                         nitems < finfo->nargs)
11754                 {
11755                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11756                         if (allargtypes)
11757                                 free(allargtypes);
11758                         allargtypes = NULL;
11759                 }
11760                 else
11761                         nallargs = nitems;
11762         }
11763
11764         if (proargmodes && *proargmodes)
11765         {
11766                 int                     nitems = 0;
11767
11768                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11769                         nitems != nallargs)
11770                 {
11771                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11772                         if (argmodes)
11773                                 free(argmodes);
11774                         argmodes = NULL;
11775                 }
11776         }
11777
11778         if (proargnames && *proargnames)
11779         {
11780                 int                     nitems = 0;
11781
11782                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11783                         nitems != nallargs)
11784                 {
11785                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11786                         if (argnames)
11787                                 free(argnames);
11788                         argnames = NULL;
11789                 }
11790         }
11791
11792         if (proconfig && *proconfig)
11793         {
11794                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11795                 {
11796                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11797                         if (configitems)
11798                                 free(configitems);
11799                         configitems = NULL;
11800                         nconfigitems = 0;
11801                 }
11802         }
11803
11804         if (funcargs)
11805         {
11806                 /* 8.4 or later; we rely on server-side code for most of the work */
11807                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11808                 funcsig = format_function_arguments(finfo, funciargs, false);
11809         }
11810         else
11811                 /* pre-8.4, do it ourselves */
11812                 funcsig = format_function_arguments_old(fout,
11813                                                                                                 finfo, nallargs, allargtypes,
11814                                                                                                 argmodes, argnames);
11815
11816         funcsig_tag = format_function_signature(fout, finfo, false);
11817
11818         if (prokind[0] == PROKIND_PROCEDURE)
11819                 keyword = "PROCEDURE";
11820         else
11821                 keyword = "FUNCTION";   /* works for window functions too */
11822
11823         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11824                                           keyword,
11825                                           fmtId(finfo->dobj.namespace->dobj.name),
11826                                           funcsig);
11827
11828         appendPQExpBuffer(q, "CREATE %s %s.%s",
11829                                           keyword,
11830                                           fmtId(finfo->dobj.namespace->dobj.name),
11831                                           funcfullsig ? funcfullsig :
11832                                           funcsig);
11833
11834         if (prokind[0] == PROKIND_PROCEDURE)
11835                  /* no result type to output */ ;
11836         else if (funcresult)
11837                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11838         else
11839         {
11840                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11841                                                                                    zeroAsOpaque);
11842                 appendPQExpBuffer(q, " RETURNS %s%s",
11843                                                   (proretset[0] == 't') ? "SETOF " : "",
11844                                                   rettypename);
11845                 free(rettypename);
11846         }
11847
11848         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11849
11850         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11851         {
11852                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11853                 int                     i;
11854
11855                 appendPQExpBufferStr(q, " TRANSFORM ");
11856                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11857                 for (i = 0; typeids[i]; i++)
11858                 {
11859                         if (i != 0)
11860                                 appendPQExpBufferStr(q, ", ");
11861                         appendPQExpBuffer(q, "FOR TYPE %s",
11862                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11863                 }
11864         }
11865
11866         if (prokind[0] == PROKIND_WINDOW)
11867                 appendPQExpBufferStr(q, " WINDOW");
11868
11869         if (provolatile[0] != PROVOLATILE_VOLATILE)
11870         {
11871                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11872                         appendPQExpBufferStr(q, " IMMUTABLE");
11873                 else if (provolatile[0] == PROVOLATILE_STABLE)
11874                         appendPQExpBufferStr(q, " STABLE");
11875                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11876                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11877                                                   finfo->dobj.name);
11878         }
11879
11880         if (proisstrict[0] == 't')
11881                 appendPQExpBufferStr(q, " STRICT");
11882
11883         if (prosecdef[0] == 't')
11884                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11885
11886         if (proleakproof[0] == 't')
11887                 appendPQExpBufferStr(q, " LEAKPROOF");
11888
11889         /*
11890          * COST and ROWS are emitted only if present and not default, so as not to
11891          * break backwards-compatibility of the dump without need.  Keep this code
11892          * in sync with the defaults in functioncmds.c.
11893          */
11894         if (strcmp(procost, "0") != 0)
11895         {
11896                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11897                 {
11898                         /* default cost is 1 */
11899                         if (strcmp(procost, "1") != 0)
11900                                 appendPQExpBuffer(q, " COST %s", procost);
11901                 }
11902                 else
11903                 {
11904                         /* default cost is 100 */
11905                         if (strcmp(procost, "100") != 0)
11906                                 appendPQExpBuffer(q, " COST %s", procost);
11907                 }
11908         }
11909         if (proretset[0] == 't' &&
11910                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11911                 appendPQExpBuffer(q, " ROWS %s", prorows);
11912
11913         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11914         {
11915                 if (proparallel[0] == PROPARALLEL_SAFE)
11916                         appendPQExpBufferStr(q, " PARALLEL SAFE");
11917                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11918                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11919                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
11920                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11921                                                   finfo->dobj.name);
11922         }
11923
11924         for (i = 0; i < nconfigitems; i++)
11925         {
11926                 /* we feel free to scribble on configitems[] here */
11927                 char       *configitem = configitems[i];
11928                 char       *pos;
11929
11930                 pos = strchr(configitem, '=');
11931                 if (pos == NULL)
11932                         continue;
11933                 *pos++ = '\0';
11934                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
11935
11936                 /*
11937                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
11938                  * by flatten_set_variable_args() before they were put into the
11939                  * proconfig array.  However, because the quoting rules used there
11940                  * aren't exactly like SQL's, we have to break the list value apart
11941                  * and then quote the elements as string literals.  (The elements may
11942                  * be double-quoted as-is, but we can't just feed them to the SQL
11943                  * parser; it would do the wrong thing with elements that are
11944                  * zero-length or longer than NAMEDATALEN.)
11945                  *
11946                  * Variables that are not so marked should just be emitted as simple
11947                  * string literals.  If the variable is not known to
11948                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
11949                  * to use GUC_LIST_QUOTE for extension variables.
11950                  */
11951                 if (variable_is_guc_list_quote(configitem))
11952                 {
11953                         char      **namelist;
11954                         char      **nameptr;
11955
11956                         /* Parse string into list of identifiers */
11957                         /* this shouldn't fail really */
11958                         if (SplitGUCList(pos, ',', &namelist))
11959                         {
11960                                 for (nameptr = namelist; *nameptr; nameptr++)
11961                                 {
11962                                         if (nameptr != namelist)
11963                                                 appendPQExpBufferStr(q, ", ");
11964                                         appendStringLiteralAH(q, *nameptr, fout);
11965                                 }
11966                         }
11967                         pg_free(namelist);
11968                 }
11969                 else
11970                         appendStringLiteralAH(q, pos, fout);
11971         }
11972
11973         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
11974
11975         if (dopt->binary_upgrade)
11976                 binary_upgrade_extension_member(q, &finfo->dobj,
11977                                                                                 keyword, funcsig,
11978                                                                                 finfo->dobj.namespace->dobj.name);
11979
11980         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11981                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11982                                          funcsig_tag,
11983                                          finfo->dobj.namespace->dobj.name,
11984                                          NULL,
11985                                          finfo->rolname, false,
11986                                          keyword, SECTION_PRE_DATA,
11987                                          q->data, delqry->data, NULL,
11988                                          NULL, 0,
11989                                          NULL, NULL);
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                                          labelq->data,
12118                                          NULL, NULL, "",
12119                                          false, "CAST", SECTION_PRE_DATA,
12120                                          defqry->data, delqry->data, NULL,
12121                                          NULL, 0,
12122                                          NULL, NULL);
12123
12124         /* Dump Cast Comments */
12125         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12126                 dumpComment(fout, "CAST", castargs->data,
12127                                         NULL, "",
12128                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12129
12130         free(sourceType);
12131         free(targetType);
12132
12133         destroyPQExpBuffer(defqry);
12134         destroyPQExpBuffer(delqry);
12135         destroyPQExpBuffer(labelq);
12136         destroyPQExpBuffer(castargs);
12137 }
12138
12139 /*
12140  * Dump a transform
12141  */
12142 static void
12143 dumpTransform(Archive *fout, TransformInfo *transform)
12144 {
12145         DumpOptions *dopt = fout->dopt;
12146         PQExpBuffer defqry;
12147         PQExpBuffer delqry;
12148         PQExpBuffer labelq;
12149         PQExpBuffer transformargs;
12150         FuncInfo   *fromsqlFuncInfo = NULL;
12151         FuncInfo   *tosqlFuncInfo = NULL;
12152         char       *lanname;
12153         char       *transformType;
12154
12155         /* Skip if not to be dumped */
12156         if (!transform->dobj.dump || dopt->dataOnly)
12157                 return;
12158
12159         /* Cannot dump if we don't have the transform functions' info */
12160         if (OidIsValid(transform->trffromsql))
12161         {
12162                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12163                 if (fromsqlFuncInfo == NULL)
12164                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12165                                                   transform->trffromsql);
12166         }
12167         if (OidIsValid(transform->trftosql))
12168         {
12169                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12170                 if (tosqlFuncInfo == NULL)
12171                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12172                                                   transform->trftosql);
12173         }
12174
12175         defqry = createPQExpBuffer();
12176         delqry = createPQExpBuffer();
12177         labelq = createPQExpBuffer();
12178         transformargs = createPQExpBuffer();
12179
12180         lanname = get_language_name(fout, transform->trflang);
12181         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12182
12183         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12184                                           transformType, lanname);
12185
12186         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12187                                           transformType, lanname);
12188
12189         if (!transform->trffromsql && !transform->trftosql)
12190                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12191
12192         if (transform->trffromsql)
12193         {
12194                 if (fromsqlFuncInfo)
12195                 {
12196                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12197
12198                         /*
12199                          * Always qualify the function name (format_function_signature
12200                          * won't qualify it).
12201                          */
12202                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12203                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12204                         free(fsig);
12205                 }
12206                 else
12207                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12208         }
12209
12210         if (transform->trftosql)
12211         {
12212                 if (transform->trffromsql)
12213                         appendPQExpBuffer(defqry, ", ");
12214
12215                 if (tosqlFuncInfo)
12216                 {
12217                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12218
12219                         /*
12220                          * Always qualify the function name (format_function_signature
12221                          * won't qualify it).
12222                          */
12223                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12224                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12225                         free(fsig);
12226                 }
12227                 else
12228                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12229         }
12230
12231         appendPQExpBuffer(defqry, ");\n");
12232
12233         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12234                                           transformType, lanname);
12235
12236         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12237                                           transformType, lanname);
12238
12239         if (dopt->binary_upgrade)
12240                 binary_upgrade_extension_member(defqry, &transform->dobj,
12241                                                                                 "TRANSFORM", transformargs->data, NULL);
12242
12243         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12244                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12245                                          labelq->data,
12246                                          NULL, NULL, "",
12247                                          false, "TRANSFORM", SECTION_PRE_DATA,
12248                                          defqry->data, delqry->data, NULL,
12249                                          transform->dobj.dependencies, transform->dobj.nDeps,
12250                                          NULL, NULL);
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                                          oprinfo->dobj.name,
12459                                          oprinfo->dobj.namespace->dobj.name,
12460                                          NULL,
12461                                          oprinfo->rolname,
12462                                          false, "OPERATOR", SECTION_PRE_DATA,
12463                                          q->data, delq->data, NULL,
12464                                          NULL, 0,
12465                                          NULL, NULL);
12466
12467         /* Dump Operator Comments */
12468         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12469                 dumpComment(fout, "OPERATOR", oprid->data,
12470                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12471                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12472
12473         PQclear(res);
12474
12475         destroyPQExpBuffer(query);
12476         destroyPQExpBuffer(q);
12477         destroyPQExpBuffer(delq);
12478         destroyPQExpBuffer(oprid);
12479         destroyPQExpBuffer(details);
12480 }
12481
12482 /*
12483  * Convert a function reference obtained from pg_operator
12484  *
12485  * Returns allocated string of what to print, or NULL if function references
12486  * is InvalidOid. Returned string is expected to be free'd by the caller.
12487  *
12488  * The input is a REGPROCEDURE display; we have to strip the argument-types
12489  * part.
12490  */
12491 static char *
12492 convertRegProcReference(Archive *fout, const char *proc)
12493 {
12494         char       *name;
12495         char       *paren;
12496         bool            inquote;
12497
12498         /* In all cases "-" means a null reference */
12499         if (strcmp(proc, "-") == 0)
12500                 return NULL;
12501
12502         name = pg_strdup(proc);
12503         /* find non-double-quoted left paren */
12504         inquote = false;
12505         for (paren = name; *paren; paren++)
12506         {
12507                 if (*paren == '(' && !inquote)
12508                 {
12509                         *paren = '\0';
12510                         break;
12511                 }
12512                 if (*paren == '"')
12513                         inquote = !inquote;
12514         }
12515         return name;
12516 }
12517
12518 /*
12519  * getFormattedOperatorName - retrieve the operator name for the
12520  * given operator OID (presented in string form).
12521  *
12522  * Returns an allocated string, or NULL if the given OID is invalid.
12523  * Caller is responsible for free'ing result string.
12524  *
12525  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12526  * useful in commands where the operator's argument types can be inferred from
12527  * context.  We always schema-qualify the name, though.  The predecessor to
12528  * this code tried to skip the schema qualification if possible, but that led
12529  * to wrong results in corner cases, such as if an operator and its negator
12530  * are in different schemas.
12531  */
12532 static char *
12533 getFormattedOperatorName(Archive *fout, const char *oproid)
12534 {
12535         OprInfo    *oprInfo;
12536
12537         /* In all cases "0" means a null reference */
12538         if (strcmp(oproid, "0") == 0)
12539                 return NULL;
12540
12541         oprInfo = findOprByOid(atooid(oproid));
12542         if (oprInfo == NULL)
12543         {
12544                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12545                                   oproid);
12546                 return NULL;
12547         }
12548
12549         return psprintf("OPERATOR(%s.%s)",
12550                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12551                                         oprInfo->dobj.name);
12552 }
12553
12554 /*
12555  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12556  *
12557  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12558  * argument lists of these functions are predetermined.  Note that the
12559  * caller should ensure we are in the proper schema, because the results
12560  * are search path dependent!
12561  */
12562 static char *
12563 convertTSFunction(Archive *fout, Oid funcOid)
12564 {
12565         char       *result;
12566         char            query[128];
12567         PGresult   *res;
12568
12569         snprintf(query, sizeof(query),
12570                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12571         res = ExecuteSqlQueryForSingleRow(fout, query);
12572
12573         result = pg_strdup(PQgetvalue(res, 0, 0));
12574
12575         PQclear(res);
12576
12577         return result;
12578 }
12579
12580 /*
12581  * dumpAccessMethod
12582  *        write out a single access method definition
12583  */
12584 static void
12585 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12586 {
12587         DumpOptions *dopt = fout->dopt;
12588         PQExpBuffer q;
12589         PQExpBuffer delq;
12590         char       *qamname;
12591
12592         /* Skip if not to be dumped */
12593         if (!aminfo->dobj.dump || dopt->dataOnly)
12594                 return;
12595
12596         q = createPQExpBuffer();
12597         delq = createPQExpBuffer();
12598
12599         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12600
12601         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12602
12603         switch (aminfo->amtype)
12604         {
12605                 case AMTYPE_INDEX:
12606                         appendPQExpBuffer(q, "TYPE INDEX ");
12607                         break;
12608                 default:
12609                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12610                                           aminfo->amtype, qamname);
12611                         destroyPQExpBuffer(q);
12612                         destroyPQExpBuffer(delq);
12613                         free(qamname);
12614                         return;
12615         }
12616
12617         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12618
12619         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12620                                           qamname);
12621
12622         if (dopt->binary_upgrade)
12623                 binary_upgrade_extension_member(q, &aminfo->dobj,
12624                                                                                 "ACCESS METHOD", qamname, NULL);
12625
12626         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12627                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12628                                          aminfo->dobj.name,
12629                                          NULL,
12630                                          NULL,
12631                                          "",
12632                                          false, "ACCESS METHOD", SECTION_PRE_DATA,
12633                                          q->data, delq->data, NULL,
12634                                          NULL, 0,
12635                                          NULL, NULL);
12636
12637         /* Dump Access Method Comments */
12638         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12639                 dumpComment(fout, "ACCESS METHOD", qamname,
12640                                         NULL, "",
12641                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12642
12643         destroyPQExpBuffer(q);
12644         destroyPQExpBuffer(delq);
12645         free(qamname);
12646 }
12647
12648 /*
12649  * dumpOpclass
12650  *        write out a single operator class definition
12651  */
12652 static void
12653 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12654 {
12655         DumpOptions *dopt = fout->dopt;
12656         PQExpBuffer query;
12657         PQExpBuffer q;
12658         PQExpBuffer delq;
12659         PQExpBuffer nameusing;
12660         PGresult   *res;
12661         int                     ntups;
12662         int                     i_opcintype;
12663         int                     i_opckeytype;
12664         int                     i_opcdefault;
12665         int                     i_opcfamily;
12666         int                     i_opcfamilyname;
12667         int                     i_opcfamilynsp;
12668         int                     i_amname;
12669         int                     i_amopstrategy;
12670         int                     i_amopreqcheck;
12671         int                     i_amopopr;
12672         int                     i_sortfamily;
12673         int                     i_sortfamilynsp;
12674         int                     i_amprocnum;
12675         int                     i_amproc;
12676         int                     i_amproclefttype;
12677         int                     i_amprocrighttype;
12678         char       *opcintype;
12679         char       *opckeytype;
12680         char       *opcdefault;
12681         char       *opcfamily;
12682         char       *opcfamilyname;
12683         char       *opcfamilynsp;
12684         char       *amname;
12685         char       *amopstrategy;
12686         char       *amopreqcheck;
12687         char       *amopopr;
12688         char       *sortfamily;
12689         char       *sortfamilynsp;
12690         char       *amprocnum;
12691         char       *amproc;
12692         char       *amproclefttype;
12693         char       *amprocrighttype;
12694         bool            needComma;
12695         int                     i;
12696
12697         /* Skip if not to be dumped */
12698         if (!opcinfo->dobj.dump || dopt->dataOnly)
12699                 return;
12700
12701         query = createPQExpBuffer();
12702         q = createPQExpBuffer();
12703         delq = createPQExpBuffer();
12704         nameusing = createPQExpBuffer();
12705
12706         /* Get additional fields from the pg_opclass row */
12707         if (fout->remoteVersion >= 80300)
12708         {
12709                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12710                                                   "opckeytype::pg_catalog.regtype, "
12711                                                   "opcdefault, opcfamily, "
12712                                                   "opfname AS opcfamilyname, "
12713                                                   "nspname AS opcfamilynsp, "
12714                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12715                                                   "FROM pg_catalog.pg_opclass c "
12716                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12717                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12718                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12719                                                   opcinfo->dobj.catId.oid);
12720         }
12721         else
12722         {
12723                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12724                                                   "opckeytype::pg_catalog.regtype, "
12725                                                   "opcdefault, NULL AS opcfamily, "
12726                                                   "NULL AS opcfamilyname, "
12727                                                   "NULL AS opcfamilynsp, "
12728                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12729                                                   "FROM pg_catalog.pg_opclass "
12730                                                   "WHERE oid = '%u'::pg_catalog.oid",
12731                                                   opcinfo->dobj.catId.oid);
12732         }
12733
12734         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12735
12736         i_opcintype = PQfnumber(res, "opcintype");
12737         i_opckeytype = PQfnumber(res, "opckeytype");
12738         i_opcdefault = PQfnumber(res, "opcdefault");
12739         i_opcfamily = PQfnumber(res, "opcfamily");
12740         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12741         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12742         i_amname = PQfnumber(res, "amname");
12743
12744         /* opcintype may still be needed after we PQclear res */
12745         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12746         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12747         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12748         /* opcfamily will still be needed after we PQclear res */
12749         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12750         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12751         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12752         /* amname will still be needed after we PQclear res */
12753         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12754
12755         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12756                                           fmtQualifiedDumpable(opcinfo));
12757         appendPQExpBuffer(delq, " USING %s;\n",
12758                                           fmtId(amname));
12759
12760         /* Build the fixed portion of the CREATE command */
12761         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12762                                           fmtQualifiedDumpable(opcinfo));
12763         if (strcmp(opcdefault, "t") == 0)
12764                 appendPQExpBufferStr(q, "DEFAULT ");
12765         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12766                                           opcintype,
12767                                           fmtId(amname));
12768         if (strlen(opcfamilyname) > 0)
12769         {
12770                 appendPQExpBufferStr(q, " FAMILY ");
12771                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12772                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12773         }
12774         appendPQExpBufferStr(q, " AS\n    ");
12775
12776         needComma = false;
12777
12778         if (strcmp(opckeytype, "-") != 0)
12779         {
12780                 appendPQExpBuffer(q, "STORAGE %s",
12781                                                   opckeytype);
12782                 needComma = true;
12783         }
12784
12785         PQclear(res);
12786
12787         /*
12788          * Now fetch and print the OPERATOR entries (pg_amop rows).
12789          *
12790          * Print only those opfamily members that are tied to the opclass by
12791          * pg_depend entries.
12792          *
12793          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12794          * older server's opclass in which it is used.  This is to avoid
12795          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12796          * older server and then reload into that old version.  This can go away
12797          * once 8.3 is so old as to not be of interest to anyone.
12798          */
12799         resetPQExpBuffer(query);
12800
12801         if (fout->remoteVersion >= 90100)
12802         {
12803                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12804                                                   "amopopr::pg_catalog.regoperator, "
12805                                                   "opfname AS sortfamily, "
12806                                                   "nspname AS sortfamilynsp "
12807                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12808                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12809                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12810                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12811                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12812                                                   "AND refobjid = '%u'::pg_catalog.oid "
12813                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12814                                                   "ORDER BY amopstrategy",
12815                                                   opcinfo->dobj.catId.oid,
12816                                                   opcfamily);
12817         }
12818         else if (fout->remoteVersion >= 80400)
12819         {
12820                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12821                                                   "amopopr::pg_catalog.regoperator, "
12822                                                   "NULL AS sortfamily, "
12823                                                   "NULL AS sortfamilynsp "
12824                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12825                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12826                                                   "AND refobjid = '%u'::pg_catalog.oid "
12827                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12828                                                   "AND objid = ao.oid "
12829                                                   "ORDER BY amopstrategy",
12830                                                   opcinfo->dobj.catId.oid);
12831         }
12832         else if (fout->remoteVersion >= 80300)
12833         {
12834                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12835                                                   "amopopr::pg_catalog.regoperator, "
12836                                                   "NULL AS sortfamily, "
12837                                                   "NULL AS sortfamilynsp "
12838                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12839                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12840                                                   "AND refobjid = '%u'::pg_catalog.oid "
12841                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12842                                                   "AND objid = ao.oid "
12843                                                   "ORDER BY amopstrategy",
12844                                                   opcinfo->dobj.catId.oid);
12845         }
12846         else
12847         {
12848                 /*
12849                  * Here, we print all entries since there are no opfamilies and hence
12850                  * no loose operators to worry about.
12851                  */
12852                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12853                                                   "amopopr::pg_catalog.regoperator, "
12854                                                   "NULL AS sortfamily, "
12855                                                   "NULL AS sortfamilynsp "
12856                                                   "FROM pg_catalog.pg_amop "
12857                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12858                                                   "ORDER BY amopstrategy",
12859                                                   opcinfo->dobj.catId.oid);
12860         }
12861
12862         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12863
12864         ntups = PQntuples(res);
12865
12866         i_amopstrategy = PQfnumber(res, "amopstrategy");
12867         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12868         i_amopopr = PQfnumber(res, "amopopr");
12869         i_sortfamily = PQfnumber(res, "sortfamily");
12870         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12871
12872         for (i = 0; i < ntups; i++)
12873         {
12874                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12875                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12876                 amopopr = PQgetvalue(res, i, i_amopopr);
12877                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12878                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12879
12880                 if (needComma)
12881                         appendPQExpBufferStr(q, " ,\n    ");
12882
12883                 appendPQExpBuffer(q, "OPERATOR %s %s",
12884                                                   amopstrategy, amopopr);
12885
12886                 if (strlen(sortfamily) > 0)
12887                 {
12888                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12889                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12890                         appendPQExpBufferStr(q, fmtId(sortfamily));
12891                 }
12892
12893                 if (strcmp(amopreqcheck, "t") == 0)
12894                         appendPQExpBufferStr(q, " RECHECK");
12895
12896                 needComma = true;
12897         }
12898
12899         PQclear(res);
12900
12901         /*
12902          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12903          *
12904          * Print only those opfamily members that are tied to the opclass by
12905          * pg_depend entries.
12906          *
12907          * We print the amproclefttype/amprocrighttype even though in most cases
12908          * the backend could deduce the right values, because of the corner case
12909          * of a btree sort support function for a cross-type comparison.  That's
12910          * only allowed in 9.2 and later, but for simplicity print them in all
12911          * versions that have the columns.
12912          */
12913         resetPQExpBuffer(query);
12914
12915         if (fout->remoteVersion >= 80300)
12916         {
12917                 appendPQExpBuffer(query, "SELECT amprocnum, "
12918                                                   "amproc::pg_catalog.regprocedure, "
12919                                                   "amproclefttype::pg_catalog.regtype, "
12920                                                   "amprocrighttype::pg_catalog.regtype "
12921                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12922                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12923                                                   "AND refobjid = '%u'::pg_catalog.oid "
12924                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12925                                                   "AND objid = ap.oid "
12926                                                   "ORDER BY amprocnum",
12927                                                   opcinfo->dobj.catId.oid);
12928         }
12929         else
12930         {
12931                 appendPQExpBuffer(query, "SELECT amprocnum, "
12932                                                   "amproc::pg_catalog.regprocedure, "
12933                                                   "'' AS amproclefttype, "
12934                                                   "'' AS amprocrighttype "
12935                                                   "FROM pg_catalog.pg_amproc "
12936                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12937                                                   "ORDER BY amprocnum",
12938                                                   opcinfo->dobj.catId.oid);
12939         }
12940
12941         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12942
12943         ntups = PQntuples(res);
12944
12945         i_amprocnum = PQfnumber(res, "amprocnum");
12946         i_amproc = PQfnumber(res, "amproc");
12947         i_amproclefttype = PQfnumber(res, "amproclefttype");
12948         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12949
12950         for (i = 0; i < ntups; i++)
12951         {
12952                 amprocnum = PQgetvalue(res, i, i_amprocnum);
12953                 amproc = PQgetvalue(res, i, i_amproc);
12954                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12955                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12956
12957                 if (needComma)
12958                         appendPQExpBufferStr(q, " ,\n    ");
12959
12960                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12961
12962                 if (*amproclefttype && *amprocrighttype)
12963                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12964
12965                 appendPQExpBuffer(q, " %s", amproc);
12966
12967                 needComma = true;
12968         }
12969
12970         PQclear(res);
12971
12972         /*
12973          * If needComma is still false it means we haven't added anything after
12974          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
12975          * clause with the same datatype.  This isn't sanctioned by the
12976          * documentation, but actually DefineOpClass will treat it as a no-op.
12977          */
12978         if (!needComma)
12979                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
12980
12981         appendPQExpBufferStr(q, ";\n");
12982
12983         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
12984         appendPQExpBuffer(nameusing, " USING %s",
12985                                           fmtId(amname));
12986
12987         if (dopt->binary_upgrade)
12988                 binary_upgrade_extension_member(q, &opcinfo->dobj,
12989                                                                                 "OPERATOR CLASS", nameusing->data,
12990                                                                                 opcinfo->dobj.namespace->dobj.name);
12991
12992         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12993                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12994                                          opcinfo->dobj.name,
12995                                          opcinfo->dobj.namespace->dobj.name,
12996                                          NULL,
12997                                          opcinfo->rolname,
12998                                          false, "OPERATOR CLASS", SECTION_PRE_DATA,
12999                                          q->data, delq->data, NULL,
13000                                          NULL, 0,
13001                                          NULL, NULL);
13002
13003         /* Dump Operator Class Comments */
13004         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13005                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13006                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13007                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13008
13009         free(opcintype);
13010         free(opcfamily);
13011         free(amname);
13012         destroyPQExpBuffer(query);
13013         destroyPQExpBuffer(q);
13014         destroyPQExpBuffer(delq);
13015         destroyPQExpBuffer(nameusing);
13016 }
13017
13018 /*
13019  * dumpOpfamily
13020  *        write out a single operator family definition
13021  *
13022  * Note: this also dumps any "loose" operator members that aren't bound to a
13023  * specific opclass within the opfamily.
13024  */
13025 static void
13026 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13027 {
13028         DumpOptions *dopt = fout->dopt;
13029         PQExpBuffer query;
13030         PQExpBuffer q;
13031         PQExpBuffer delq;
13032         PQExpBuffer nameusing;
13033         PGresult   *res;
13034         PGresult   *res_ops;
13035         PGresult   *res_procs;
13036         int                     ntups;
13037         int                     i_amname;
13038         int                     i_amopstrategy;
13039         int                     i_amopreqcheck;
13040         int                     i_amopopr;
13041         int                     i_sortfamily;
13042         int                     i_sortfamilynsp;
13043         int                     i_amprocnum;
13044         int                     i_amproc;
13045         int                     i_amproclefttype;
13046         int                     i_amprocrighttype;
13047         char       *amname;
13048         char       *amopstrategy;
13049         char       *amopreqcheck;
13050         char       *amopopr;
13051         char       *sortfamily;
13052         char       *sortfamilynsp;
13053         char       *amprocnum;
13054         char       *amproc;
13055         char       *amproclefttype;
13056         char       *amprocrighttype;
13057         bool            needComma;
13058         int                     i;
13059
13060         /* Skip if not to be dumped */
13061         if (!opfinfo->dobj.dump || dopt->dataOnly)
13062                 return;
13063
13064         query = createPQExpBuffer();
13065         q = createPQExpBuffer();
13066         delq = createPQExpBuffer();
13067         nameusing = createPQExpBuffer();
13068
13069         /*
13070          * Fetch only those opfamily members that are tied directly to the
13071          * opfamily by pg_depend entries.
13072          *
13073          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13074          * older server's opclass in which it is used.  This is to avoid
13075          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13076          * older server and then reload into that old version.  This can go away
13077          * once 8.3 is so old as to not be of interest to anyone.
13078          */
13079         if (fout->remoteVersion >= 90100)
13080         {
13081                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13082                                                   "amopopr::pg_catalog.regoperator, "
13083                                                   "opfname AS sortfamily, "
13084                                                   "nspname AS sortfamilynsp "
13085                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13086                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13087                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13088                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13089                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13090                                                   "AND refobjid = '%u'::pg_catalog.oid "
13091                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13092                                                   "ORDER BY amopstrategy",
13093                                                   opfinfo->dobj.catId.oid,
13094                                                   opfinfo->dobj.catId.oid);
13095         }
13096         else if (fout->remoteVersion >= 80400)
13097         {
13098                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13099                                                   "amopopr::pg_catalog.regoperator, "
13100                                                   "NULL AS sortfamily, "
13101                                                   "NULL AS sortfamilynsp "
13102                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13103                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13104                                                   "AND refobjid = '%u'::pg_catalog.oid "
13105                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13106                                                   "AND objid = ao.oid "
13107                                                   "ORDER BY amopstrategy",
13108                                                   opfinfo->dobj.catId.oid);
13109         }
13110         else
13111         {
13112                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13113                                                   "amopopr::pg_catalog.regoperator, "
13114                                                   "NULL AS sortfamily, "
13115                                                   "NULL AS sortfamilynsp "
13116                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13117                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13118                                                   "AND refobjid = '%u'::pg_catalog.oid "
13119                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13120                                                   "AND objid = ao.oid "
13121                                                   "ORDER BY amopstrategy",
13122                                                   opfinfo->dobj.catId.oid);
13123         }
13124
13125         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13126
13127         resetPQExpBuffer(query);
13128
13129         appendPQExpBuffer(query, "SELECT amprocnum, "
13130                                           "amproc::pg_catalog.regprocedure, "
13131                                           "amproclefttype::pg_catalog.regtype, "
13132                                           "amprocrighttype::pg_catalog.regtype "
13133                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13134                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13135                                           "AND refobjid = '%u'::pg_catalog.oid "
13136                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13137                                           "AND objid = ap.oid "
13138                                           "ORDER BY amprocnum",
13139                                           opfinfo->dobj.catId.oid);
13140
13141         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13142
13143         /* Get additional fields from the pg_opfamily row */
13144         resetPQExpBuffer(query);
13145
13146         appendPQExpBuffer(query, "SELECT "
13147                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13148                                           "FROM pg_catalog.pg_opfamily "
13149                                           "WHERE oid = '%u'::pg_catalog.oid",
13150                                           opfinfo->dobj.catId.oid);
13151
13152         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13153
13154         i_amname = PQfnumber(res, "amname");
13155
13156         /* amname will still be needed after we PQclear res */
13157         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13158
13159         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13160                                           fmtQualifiedDumpable(opfinfo));
13161         appendPQExpBuffer(delq, " USING %s;\n",
13162                                           fmtId(amname));
13163
13164         /* Build the fixed portion of the CREATE command */
13165         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13166                                           fmtQualifiedDumpable(opfinfo));
13167         appendPQExpBuffer(q, " USING %s;\n",
13168                                           fmtId(amname));
13169
13170         PQclear(res);
13171
13172         /* Do we need an ALTER to add loose members? */
13173         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13174         {
13175                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13176                                                   fmtQualifiedDumpable(opfinfo));
13177                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13178                                                   fmtId(amname));
13179
13180                 needComma = false;
13181
13182                 /*
13183                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13184                  */
13185                 ntups = PQntuples(res_ops);
13186
13187                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13188                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13189                 i_amopopr = PQfnumber(res_ops, "amopopr");
13190                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13191                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13192
13193                 for (i = 0; i < ntups; i++)
13194                 {
13195                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13196                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13197                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13198                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13199                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13200
13201                         if (needComma)
13202                                 appendPQExpBufferStr(q, " ,\n    ");
13203
13204                         appendPQExpBuffer(q, "OPERATOR %s %s",
13205                                                           amopstrategy, amopopr);
13206
13207                         if (strlen(sortfamily) > 0)
13208                         {
13209                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13210                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13211                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13212                         }
13213
13214                         if (strcmp(amopreqcheck, "t") == 0)
13215                                 appendPQExpBufferStr(q, " RECHECK");
13216
13217                         needComma = true;
13218                 }
13219
13220                 /*
13221                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13222                  */
13223                 ntups = PQntuples(res_procs);
13224
13225                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13226                 i_amproc = PQfnumber(res_procs, "amproc");
13227                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13228                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13229
13230                 for (i = 0; i < ntups; i++)
13231                 {
13232                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13233                         amproc = PQgetvalue(res_procs, i, i_amproc);
13234                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13235                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13236
13237                         if (needComma)
13238                                 appendPQExpBufferStr(q, " ,\n    ");
13239
13240                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13241                                                           amprocnum, amproclefttype, amprocrighttype,
13242                                                           amproc);
13243
13244                         needComma = true;
13245                 }
13246
13247                 appendPQExpBufferStr(q, ";\n");
13248         }
13249
13250         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13251         appendPQExpBuffer(nameusing, " USING %s",
13252                                           fmtId(amname));
13253
13254         if (dopt->binary_upgrade)
13255                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13256                                                                                 "OPERATOR FAMILY", nameusing->data,
13257                                                                                 opfinfo->dobj.namespace->dobj.name);
13258
13259         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13260                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13261                                          opfinfo->dobj.name,
13262                                          opfinfo->dobj.namespace->dobj.name,
13263                                          NULL,
13264                                          opfinfo->rolname,
13265                                          false, "OPERATOR FAMILY", SECTION_PRE_DATA,
13266                                          q->data, delq->data, NULL,
13267                                          NULL, 0,
13268                                          NULL, NULL);
13269
13270         /* Dump Operator Family Comments */
13271         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13272                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13273                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13274                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13275
13276         free(amname);
13277         PQclear(res_ops);
13278         PQclear(res_procs);
13279         destroyPQExpBuffer(query);
13280         destroyPQExpBuffer(q);
13281         destroyPQExpBuffer(delq);
13282         destroyPQExpBuffer(nameusing);
13283 }
13284
13285 /*
13286  * dumpCollation
13287  *        write out a single collation definition
13288  */
13289 static void
13290 dumpCollation(Archive *fout, CollInfo *collinfo)
13291 {
13292         DumpOptions *dopt = fout->dopt;
13293         PQExpBuffer query;
13294         PQExpBuffer q;
13295         PQExpBuffer delq;
13296         char       *qcollname;
13297         PGresult   *res;
13298         int                     i_collprovider;
13299         int                     i_collcollate;
13300         int                     i_collctype;
13301         const char *collprovider;
13302         const char *collcollate;
13303         const char *collctype;
13304
13305         /* Skip if not to be dumped */
13306         if (!collinfo->dobj.dump || dopt->dataOnly)
13307                 return;
13308
13309         query = createPQExpBuffer();
13310         q = createPQExpBuffer();
13311         delq = createPQExpBuffer();
13312
13313         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13314
13315         /* Get collation-specific details */
13316         if (fout->remoteVersion >= 100000)
13317                 appendPQExpBuffer(query, "SELECT "
13318                                                   "collprovider, "
13319                                                   "collcollate, "
13320                                                   "collctype, "
13321                                                   "collversion "
13322                                                   "FROM pg_catalog.pg_collation c "
13323                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13324                                                   collinfo->dobj.catId.oid);
13325         else
13326                 appendPQExpBuffer(query, "SELECT "
13327                                                   "'c' AS collprovider, "
13328                                                   "collcollate, "
13329                                                   "collctype, "
13330                                                   "NULL AS collversion "
13331                                                   "FROM pg_catalog.pg_collation c "
13332                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13333                                                   collinfo->dobj.catId.oid);
13334
13335         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13336
13337         i_collprovider = PQfnumber(res, "collprovider");
13338         i_collcollate = PQfnumber(res, "collcollate");
13339         i_collctype = PQfnumber(res, "collctype");
13340
13341         collprovider = PQgetvalue(res, 0, i_collprovider);
13342         collcollate = PQgetvalue(res, 0, i_collcollate);
13343         collctype = PQgetvalue(res, 0, i_collctype);
13344
13345         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13346                                           fmtQualifiedDumpable(collinfo));
13347
13348         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13349                                           fmtQualifiedDumpable(collinfo));
13350
13351         appendPQExpBufferStr(q, "provider = ");
13352         if (collprovider[0] == 'c')
13353                 appendPQExpBufferStr(q, "libc");
13354         else if (collprovider[0] == 'i')
13355                 appendPQExpBufferStr(q, "icu");
13356         else if (collprovider[0] == 'd')
13357                 /* to allow dumping pg_catalog; not accepted on input */
13358                 appendPQExpBufferStr(q, "default");
13359         else
13360                 exit_horribly(NULL,
13361                                           "unrecognized collation provider: %s\n",
13362                                           collprovider);
13363
13364         if (strcmp(collcollate, collctype) == 0)
13365         {
13366                 appendPQExpBufferStr(q, ", locale = ");
13367                 appendStringLiteralAH(q, collcollate, fout);
13368         }
13369         else
13370         {
13371                 appendPQExpBufferStr(q, ", lc_collate = ");
13372                 appendStringLiteralAH(q, collcollate, fout);
13373                 appendPQExpBufferStr(q, ", lc_ctype = ");
13374                 appendStringLiteralAH(q, collctype, fout);
13375         }
13376
13377         /*
13378          * For binary upgrade, carry over the collation version.  For normal
13379          * dump/restore, omit the version, so that it is computed upon restore.
13380          */
13381         if (dopt->binary_upgrade)
13382         {
13383                 int                     i_collversion;
13384
13385                 i_collversion = PQfnumber(res, "collversion");
13386                 if (!PQgetisnull(res, 0, i_collversion))
13387                 {
13388                         appendPQExpBufferStr(q, ", version = ");
13389                         appendStringLiteralAH(q,
13390                                                                   PQgetvalue(res, 0, i_collversion),
13391                                                                   fout);
13392                 }
13393         }
13394
13395         appendPQExpBufferStr(q, ");\n");
13396
13397         if (dopt->binary_upgrade)
13398                 binary_upgrade_extension_member(q, &collinfo->dobj,
13399                                                                                 "COLLATION", qcollname,
13400                                                                                 collinfo->dobj.namespace->dobj.name);
13401
13402         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13403                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13404                                          collinfo->dobj.name,
13405                                          collinfo->dobj.namespace->dobj.name,
13406                                          NULL,
13407                                          collinfo->rolname,
13408                                          false, "COLLATION", SECTION_PRE_DATA,
13409                                          q->data, delq->data, NULL,
13410                                          NULL, 0,
13411                                          NULL, NULL);
13412
13413         /* Dump Collation Comments */
13414         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13415                 dumpComment(fout, "COLLATION", qcollname,
13416                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13417                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13418
13419         PQclear(res);
13420
13421         destroyPQExpBuffer(query);
13422         destroyPQExpBuffer(q);
13423         destroyPQExpBuffer(delq);
13424         free(qcollname);
13425 }
13426
13427 /*
13428  * dumpConversion
13429  *        write out a single conversion definition
13430  */
13431 static void
13432 dumpConversion(Archive *fout, ConvInfo *convinfo)
13433 {
13434         DumpOptions *dopt = fout->dopt;
13435         PQExpBuffer query;
13436         PQExpBuffer q;
13437         PQExpBuffer delq;
13438         char       *qconvname;
13439         PGresult   *res;
13440         int                     i_conforencoding;
13441         int                     i_contoencoding;
13442         int                     i_conproc;
13443         int                     i_condefault;
13444         const char *conforencoding;
13445         const char *contoencoding;
13446         const char *conproc;
13447         bool            condefault;
13448
13449         /* Skip if not to be dumped */
13450         if (!convinfo->dobj.dump || dopt->dataOnly)
13451                 return;
13452
13453         query = createPQExpBuffer();
13454         q = createPQExpBuffer();
13455         delq = createPQExpBuffer();
13456
13457         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13458
13459         /* Get conversion-specific details */
13460         appendPQExpBuffer(query, "SELECT "
13461                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13462                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13463                                           "conproc, condefault "
13464                                           "FROM pg_catalog.pg_conversion c "
13465                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13466                                           convinfo->dobj.catId.oid);
13467
13468         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13469
13470         i_conforencoding = PQfnumber(res, "conforencoding");
13471         i_contoencoding = PQfnumber(res, "contoencoding");
13472         i_conproc = PQfnumber(res, "conproc");
13473         i_condefault = PQfnumber(res, "condefault");
13474
13475         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13476         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13477         conproc = PQgetvalue(res, 0, i_conproc);
13478         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13479
13480         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13481                                           fmtQualifiedDumpable(convinfo));
13482
13483         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13484                                           (condefault) ? "DEFAULT " : "",
13485                                           fmtQualifiedDumpable(convinfo));
13486         appendStringLiteralAH(q, conforencoding, fout);
13487         appendPQExpBufferStr(q, " TO ");
13488         appendStringLiteralAH(q, contoencoding, fout);
13489         /* regproc output is already sufficiently quoted */
13490         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13491
13492         if (dopt->binary_upgrade)
13493                 binary_upgrade_extension_member(q, &convinfo->dobj,
13494                                                                                 "CONVERSION", qconvname,
13495                                                                                 convinfo->dobj.namespace->dobj.name);
13496
13497         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13498                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13499                                          convinfo->dobj.name,
13500                                          convinfo->dobj.namespace->dobj.name,
13501                                          NULL,
13502                                          convinfo->rolname,
13503                                          false, "CONVERSION", SECTION_PRE_DATA,
13504                                          q->data, delq->data, NULL,
13505                                          NULL, 0,
13506                                          NULL, NULL);
13507
13508         /* Dump Conversion Comments */
13509         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13510                 dumpComment(fout, "CONVERSION", qconvname,
13511                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13512                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13513
13514         PQclear(res);
13515
13516         destroyPQExpBuffer(query);
13517         destroyPQExpBuffer(q);
13518         destroyPQExpBuffer(delq);
13519         free(qconvname);
13520 }
13521
13522 /*
13523  * format_aggregate_signature: generate aggregate name and argument list
13524  *
13525  * The argument type names are qualified if needed.  The aggregate name
13526  * is never qualified.
13527  */
13528 static char *
13529 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13530 {
13531         PQExpBufferData buf;
13532         int                     j;
13533
13534         initPQExpBuffer(&buf);
13535         if (honor_quotes)
13536                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13537         else
13538                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13539
13540         if (agginfo->aggfn.nargs == 0)
13541                 appendPQExpBuffer(&buf, "(*)");
13542         else
13543         {
13544                 appendPQExpBufferChar(&buf, '(');
13545                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13546                 {
13547                         char       *typname;
13548
13549                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13550                                                                                    zeroAsOpaque);
13551
13552                         appendPQExpBuffer(&buf, "%s%s",
13553                                                           (j > 0) ? ", " : "",
13554                                                           typname);
13555                         free(typname);
13556                 }
13557                 appendPQExpBufferChar(&buf, ')');
13558         }
13559         return buf.data;
13560 }
13561
13562 /*
13563  * dumpAgg
13564  *        write out a single aggregate definition
13565  */
13566 static void
13567 dumpAgg(Archive *fout, AggInfo *agginfo)
13568 {
13569         DumpOptions *dopt = fout->dopt;
13570         PQExpBuffer query;
13571         PQExpBuffer q;
13572         PQExpBuffer delq;
13573         PQExpBuffer details;
13574         char       *aggsig;                     /* identity signature */
13575         char       *aggfullsig = NULL;  /* full signature */
13576         char       *aggsig_tag;
13577         PGresult   *res;
13578         int                     i_aggtransfn;
13579         int                     i_aggfinalfn;
13580         int                     i_aggcombinefn;
13581         int                     i_aggserialfn;
13582         int                     i_aggdeserialfn;
13583         int                     i_aggmtransfn;
13584         int                     i_aggminvtransfn;
13585         int                     i_aggmfinalfn;
13586         int                     i_aggfinalextra;
13587         int                     i_aggmfinalextra;
13588         int                     i_aggfinalmodify;
13589         int                     i_aggmfinalmodify;
13590         int                     i_aggsortop;
13591         int                     i_aggkind;
13592         int                     i_aggtranstype;
13593         int                     i_aggtransspace;
13594         int                     i_aggmtranstype;
13595         int                     i_aggmtransspace;
13596         int                     i_agginitval;
13597         int                     i_aggminitval;
13598         int                     i_convertok;
13599         int                     i_proparallel;
13600         const char *aggtransfn;
13601         const char *aggfinalfn;
13602         const char *aggcombinefn;
13603         const char *aggserialfn;
13604         const char *aggdeserialfn;
13605         const char *aggmtransfn;
13606         const char *aggminvtransfn;
13607         const char *aggmfinalfn;
13608         bool            aggfinalextra;
13609         bool            aggmfinalextra;
13610         char            aggfinalmodify;
13611         char            aggmfinalmodify;
13612         const char *aggsortop;
13613         char       *aggsortconvop;
13614         char            aggkind;
13615         const char *aggtranstype;
13616         const char *aggtransspace;
13617         const char *aggmtranstype;
13618         const char *aggmtransspace;
13619         const char *agginitval;
13620         const char *aggminitval;
13621         bool            convertok;
13622         const char *proparallel;
13623         char            defaultfinalmodify;
13624
13625         /* Skip if not to be dumped */
13626         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13627                 return;
13628
13629         query = createPQExpBuffer();
13630         q = createPQExpBuffer();
13631         delq = createPQExpBuffer();
13632         details = createPQExpBuffer();
13633
13634         /* Get aggregate-specific details */
13635         if (fout->remoteVersion >= 110000)
13636         {
13637                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13638                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13639                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13640                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13641                                                   "aggfinalextra, aggmfinalextra, "
13642                                                   "aggfinalmodify, aggmfinalmodify, "
13643                                                   "aggsortop, "
13644                                                   "aggkind, "
13645                                                   "aggtransspace, agginitval, "
13646                                                   "aggmtransspace, aggminitval, "
13647                                                   "true AS convertok, "
13648                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13649                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13650                                                   "p.proparallel "
13651                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13652                                                   "WHERE a.aggfnoid = p.oid "
13653                                                   "AND p.oid = '%u'::pg_catalog.oid",
13654                                                   agginfo->aggfn.dobj.catId.oid);
13655         }
13656         else if (fout->remoteVersion >= 90600)
13657         {
13658                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13659                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13660                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13661                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13662                                                   "aggfinalextra, aggmfinalextra, "
13663                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13664                                                   "aggsortop, "
13665                                                   "aggkind, "
13666                                                   "aggtransspace, agginitval, "
13667                                                   "aggmtransspace, aggminitval, "
13668                                                   "true AS convertok, "
13669                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13670                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13671                                                   "p.proparallel "
13672                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13673                                                   "WHERE a.aggfnoid = p.oid "
13674                                                   "AND p.oid = '%u'::pg_catalog.oid",
13675                                                   agginfo->aggfn.dobj.catId.oid);
13676         }
13677         else if (fout->remoteVersion >= 90400)
13678         {
13679                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13680                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13681                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13682                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13683                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13684                                                   "aggfinalextra, aggmfinalextra, "
13685                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13686                                                   "aggsortop, "
13687                                                   "aggkind, "
13688                                                   "aggtransspace, agginitval, "
13689                                                   "aggmtransspace, aggminitval, "
13690                                                   "true AS convertok, "
13691                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13692                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13693                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13694                                                   "WHERE a.aggfnoid = p.oid "
13695                                                   "AND p.oid = '%u'::pg_catalog.oid",
13696                                                   agginfo->aggfn.dobj.catId.oid);
13697         }
13698         else if (fout->remoteVersion >= 80400)
13699         {
13700                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13701                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13702                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13703                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13704                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13705                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13706                                                   "false AS aggmfinalextra, "
13707                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13708                                                   "aggsortop, "
13709                                                   "'n' AS aggkind, "
13710                                                   "0 AS aggtransspace, agginitval, "
13711                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13712                                                   "true AS convertok, "
13713                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13714                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13715                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13716                                                   "WHERE a.aggfnoid = p.oid "
13717                                                   "AND p.oid = '%u'::pg_catalog.oid",
13718                                                   agginfo->aggfn.dobj.catId.oid);
13719         }
13720         else if (fout->remoteVersion >= 80100)
13721         {
13722                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13723                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13724                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13725                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13726                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13727                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13728                                                   "false AS aggmfinalextra, "
13729                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13730                                                   "aggsortop, "
13731                                                   "'n' AS aggkind, "
13732                                                   "0 AS aggtransspace, agginitval, "
13733                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13734                                                   "true AS convertok "
13735                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13736                                                   "WHERE a.aggfnoid = p.oid "
13737                                                   "AND p.oid = '%u'::pg_catalog.oid",
13738                                                   agginfo->aggfn.dobj.catId.oid);
13739         }
13740         else
13741         {
13742                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13743                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13744                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13745                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13746                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13747                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13748                                                   "false AS aggmfinalextra, "
13749                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13750                                                   "0 AS aggsortop, "
13751                                                   "'n' AS aggkind, "
13752                                                   "0 AS aggtransspace, agginitval, "
13753                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13754                                                   "true AS convertok "
13755                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13756                                                   "WHERE a.aggfnoid = p.oid "
13757                                                   "AND p.oid = '%u'::pg_catalog.oid",
13758                                                   agginfo->aggfn.dobj.catId.oid);
13759         }
13760
13761         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13762
13763         i_aggtransfn = PQfnumber(res, "aggtransfn");
13764         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13765         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13766         i_aggserialfn = PQfnumber(res, "aggserialfn");
13767         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13768         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13769         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13770         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13771         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13772         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13773         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13774         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13775         i_aggsortop = PQfnumber(res, "aggsortop");
13776         i_aggkind = PQfnumber(res, "aggkind");
13777         i_aggtranstype = PQfnumber(res, "aggtranstype");
13778         i_aggtransspace = PQfnumber(res, "aggtransspace");
13779         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13780         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13781         i_agginitval = PQfnumber(res, "agginitval");
13782         i_aggminitval = PQfnumber(res, "aggminitval");
13783         i_convertok = PQfnumber(res, "convertok");
13784         i_proparallel = PQfnumber(res, "proparallel");
13785
13786         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13787         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13788         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13789         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13790         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13791         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13792         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13793         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13794         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13795         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13796         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13797         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13798         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13799         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13800         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13801         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13802         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13803         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13804         agginitval = PQgetvalue(res, 0, i_agginitval);
13805         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13806         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13807
13808         if (fout->remoteVersion >= 80400)
13809         {
13810                 /* 8.4 or later; we rely on server-side code for most of the work */
13811                 char       *funcargs;
13812                 char       *funciargs;
13813
13814                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13815                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13816                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13817                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13818         }
13819         else
13820                 /* pre-8.4, do it ourselves */
13821                 aggsig = format_aggregate_signature(agginfo, fout, true);
13822
13823         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13824
13825         if (i_proparallel != -1)
13826                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13827         else
13828                 proparallel = NULL;
13829
13830         if (!convertok)
13831         {
13832                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13833                                   aggsig);
13834
13835                 if (aggfullsig)
13836                         free(aggfullsig);
13837
13838                 free(aggsig);
13839
13840                 return;
13841         }
13842
13843         /* identify default modify flag for aggkind (must match DefineAggregate) */
13844         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13845         /* replace omitted flags for old versions */
13846         if (aggfinalmodify == '0')
13847                 aggfinalmodify = defaultfinalmodify;
13848         if (aggmfinalmodify == '0')
13849                 aggmfinalmodify = defaultfinalmodify;
13850
13851         /* regproc and regtype output is already sufficiently quoted */
13852         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13853                                           aggtransfn, aggtranstype);
13854
13855         if (strcmp(aggtransspace, "0") != 0)
13856         {
13857                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13858                                                   aggtransspace);
13859         }
13860
13861         if (!PQgetisnull(res, 0, i_agginitval))
13862         {
13863                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13864                 appendStringLiteralAH(details, agginitval, fout);
13865         }
13866
13867         if (strcmp(aggfinalfn, "-") != 0)
13868         {
13869                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13870                                                   aggfinalfn);
13871                 if (aggfinalextra)
13872                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13873                 if (aggfinalmodify != defaultfinalmodify)
13874                 {
13875                         switch (aggfinalmodify)
13876                         {
13877                                 case AGGMODIFY_READ_ONLY:
13878                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13879                                         break;
13880                                 case AGGMODIFY_SHAREABLE:
13881                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
13882                                         break;
13883                                 case AGGMODIFY_READ_WRITE:
13884                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13885                                         break;
13886                                 default:
13887                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
13888                                                                   agginfo->aggfn.dobj.name);
13889                                         break;
13890                         }
13891                 }
13892         }
13893
13894         if (strcmp(aggcombinefn, "-") != 0)
13895                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13896
13897         if (strcmp(aggserialfn, "-") != 0)
13898                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13899
13900         if (strcmp(aggdeserialfn, "-") != 0)
13901                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13902
13903         if (strcmp(aggmtransfn, "-") != 0)
13904         {
13905                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13906                                                   aggmtransfn,
13907                                                   aggminvtransfn,
13908                                                   aggmtranstype);
13909         }
13910
13911         if (strcmp(aggmtransspace, "0") != 0)
13912         {
13913                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
13914                                                   aggmtransspace);
13915         }
13916
13917         if (!PQgetisnull(res, 0, i_aggminitval))
13918         {
13919                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
13920                 appendStringLiteralAH(details, aggminitval, fout);
13921         }
13922
13923         if (strcmp(aggmfinalfn, "-") != 0)
13924         {
13925                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
13926                                                   aggmfinalfn);
13927                 if (aggmfinalextra)
13928                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
13929                 if (aggmfinalmodify != defaultfinalmodify)
13930                 {
13931                         switch (aggmfinalmodify)
13932                         {
13933                                 case AGGMODIFY_READ_ONLY:
13934                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
13935                                         break;
13936                                 case AGGMODIFY_SHAREABLE:
13937                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
13938                                         break;
13939                                 case AGGMODIFY_READ_WRITE:
13940                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
13941                                         break;
13942                                 default:
13943                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
13944                                                                   agginfo->aggfn.dobj.name);
13945                                         break;
13946                         }
13947                 }
13948         }
13949
13950         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
13951         if (aggsortconvop)
13952         {
13953                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
13954                                                   aggsortconvop);
13955                 free(aggsortconvop);
13956         }
13957
13958         if (aggkind == AGGKIND_HYPOTHETICAL)
13959                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
13960
13961         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13962         {
13963                 if (proparallel[0] == PROPARALLEL_SAFE)
13964                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
13965                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13966                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
13967                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13968                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13969                                                   agginfo->aggfn.dobj.name);
13970         }
13971
13972         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13973                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13974                                           aggsig);
13975
13976         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
13977                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13978                                           aggfullsig ? aggfullsig : aggsig, details->data);
13979
13980         if (dopt->binary_upgrade)
13981                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
13982                                                                                 "AGGREGATE", aggsig,
13983                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
13984
13985         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13986                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13987                                          agginfo->aggfn.dobj.dumpId,
13988                                          aggsig_tag,
13989                                          agginfo->aggfn.dobj.namespace->dobj.name,
13990                                          NULL,
13991                                          agginfo->aggfn.rolname,
13992                                          false, "AGGREGATE", SECTION_PRE_DATA,
13993                                          q->data, delq->data, NULL,
13994                                          NULL, 0,
13995                                          NULL, NULL);
13996
13997         /* Dump Aggregate Comments */
13998         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13999                 dumpComment(fout, "AGGREGATE", aggsig,
14000                                         agginfo->aggfn.dobj.namespace->dobj.name,
14001                                         agginfo->aggfn.rolname,
14002                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14003
14004         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14005                 dumpSecLabel(fout, "AGGREGATE", aggsig,
14006                                          agginfo->aggfn.dobj.namespace->dobj.name,
14007                                          agginfo->aggfn.rolname,
14008                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14009
14010         /*
14011          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14012          * command look like a function's GRANT; in particular this affects the
14013          * syntax for zero-argument aggregates and ordered-set aggregates.
14014          */
14015         free(aggsig);
14016
14017         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14018
14019         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14020                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14021                                 "FUNCTION", aggsig, NULL,
14022                                 agginfo->aggfn.dobj.namespace->dobj.name,
14023                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14024                                 agginfo->aggfn.rproacl,
14025                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14026
14027         free(aggsig);
14028         if (aggfullsig)
14029                 free(aggfullsig);
14030         free(aggsig_tag);
14031
14032         PQclear(res);
14033
14034         destroyPQExpBuffer(query);
14035         destroyPQExpBuffer(q);
14036         destroyPQExpBuffer(delq);
14037         destroyPQExpBuffer(details);
14038 }
14039
14040 /*
14041  * dumpTSParser
14042  *        write out a single text search parser
14043  */
14044 static void
14045 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14046 {
14047         DumpOptions *dopt = fout->dopt;
14048         PQExpBuffer q;
14049         PQExpBuffer delq;
14050         char       *qprsname;
14051
14052         /* Skip if not to be dumped */
14053         if (!prsinfo->dobj.dump || dopt->dataOnly)
14054                 return;
14055
14056         q = createPQExpBuffer();
14057         delq = createPQExpBuffer();
14058
14059         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14060
14061         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14062                                           fmtQualifiedDumpable(prsinfo));
14063
14064         appendPQExpBuffer(q, "    START = %s,\n",
14065                                           convertTSFunction(fout, prsinfo->prsstart));
14066         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14067                                           convertTSFunction(fout, prsinfo->prstoken));
14068         appendPQExpBuffer(q, "    END = %s,\n",
14069                                           convertTSFunction(fout, prsinfo->prsend));
14070         if (prsinfo->prsheadline != InvalidOid)
14071                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14072                                                   convertTSFunction(fout, prsinfo->prsheadline));
14073         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14074                                           convertTSFunction(fout, prsinfo->prslextype));
14075
14076         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14077                                           fmtQualifiedDumpable(prsinfo));
14078
14079         if (dopt->binary_upgrade)
14080                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14081                                                                                 "TEXT SEARCH PARSER", qprsname,
14082                                                                                 prsinfo->dobj.namespace->dobj.name);
14083
14084         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14085                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14086                                          prsinfo->dobj.name,
14087                                          prsinfo->dobj.namespace->dobj.name,
14088                                          NULL,
14089                                          "",
14090                                          false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
14091                                          q->data, delq->data, NULL,
14092                                          NULL, 0,
14093                                          NULL, NULL);
14094
14095         /* Dump Parser Comments */
14096         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14097                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14098                                         prsinfo->dobj.namespace->dobj.name, "",
14099                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14100
14101         destroyPQExpBuffer(q);
14102         destroyPQExpBuffer(delq);
14103         free(qprsname);
14104 }
14105
14106 /*
14107  * dumpTSDictionary
14108  *        write out a single text search dictionary
14109  */
14110 static void
14111 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14112 {
14113         DumpOptions *dopt = fout->dopt;
14114         PQExpBuffer q;
14115         PQExpBuffer delq;
14116         PQExpBuffer query;
14117         char       *qdictname;
14118         PGresult   *res;
14119         char       *nspname;
14120         char       *tmplname;
14121
14122         /* Skip if not to be dumped */
14123         if (!dictinfo->dobj.dump || dopt->dataOnly)
14124                 return;
14125
14126         q = createPQExpBuffer();
14127         delq = createPQExpBuffer();
14128         query = createPQExpBuffer();
14129
14130         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14131
14132         /* Fetch name and namespace of the dictionary's template */
14133         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14134                                           "FROM pg_ts_template p, pg_namespace n "
14135                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14136                                           dictinfo->dicttemplate);
14137         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14138         nspname = PQgetvalue(res, 0, 0);
14139         tmplname = PQgetvalue(res, 0, 1);
14140
14141         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14142                                           fmtQualifiedDumpable(dictinfo));
14143
14144         appendPQExpBufferStr(q, "    TEMPLATE = ");
14145         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14146         appendPQExpBufferStr(q, fmtId(tmplname));
14147
14148         PQclear(res);
14149
14150         /* the dictinitoption can be dumped straight into the command */
14151         if (dictinfo->dictinitoption)
14152                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14153
14154         appendPQExpBufferStr(q, " );\n");
14155
14156         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14157                                           fmtQualifiedDumpable(dictinfo));
14158
14159         if (dopt->binary_upgrade)
14160                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14161                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14162                                                                                 dictinfo->dobj.namespace->dobj.name);
14163
14164         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14165                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14166                                          dictinfo->dobj.name,
14167                                          dictinfo->dobj.namespace->dobj.name,
14168                                          NULL,
14169                                          dictinfo->rolname,
14170                                          false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
14171                                          q->data, delq->data, NULL,
14172                                          NULL, 0,
14173                                          NULL, NULL);
14174
14175         /* Dump Dictionary Comments */
14176         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14177                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14178                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14179                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14180
14181         destroyPQExpBuffer(q);
14182         destroyPQExpBuffer(delq);
14183         destroyPQExpBuffer(query);
14184         free(qdictname);
14185 }
14186
14187 /*
14188  * dumpTSTemplate
14189  *        write out a single text search template
14190  */
14191 static void
14192 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14193 {
14194         DumpOptions *dopt = fout->dopt;
14195         PQExpBuffer q;
14196         PQExpBuffer delq;
14197         char       *qtmplname;
14198
14199         /* Skip if not to be dumped */
14200         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14201                 return;
14202
14203         q = createPQExpBuffer();
14204         delq = createPQExpBuffer();
14205
14206         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14207
14208         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14209                                           fmtQualifiedDumpable(tmplinfo));
14210
14211         if (tmplinfo->tmplinit != InvalidOid)
14212                 appendPQExpBuffer(q, "    INIT = %s,\n",
14213                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14214         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14215                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14216
14217         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14218                                           fmtQualifiedDumpable(tmplinfo));
14219
14220         if (dopt->binary_upgrade)
14221                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14222                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14223                                                                                 tmplinfo->dobj.namespace->dobj.name);
14224
14225         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14226                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14227                                          tmplinfo->dobj.name,
14228                                          tmplinfo->dobj.namespace->dobj.name,
14229                                          NULL,
14230                                          "",
14231                                          false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
14232                                          q->data, delq->data, NULL,
14233                                          NULL, 0,
14234                                          NULL, NULL);
14235
14236         /* Dump Template Comments */
14237         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14238                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14239                                         tmplinfo->dobj.namespace->dobj.name, "",
14240                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14241
14242         destroyPQExpBuffer(q);
14243         destroyPQExpBuffer(delq);
14244         free(qtmplname);
14245 }
14246
14247 /*
14248  * dumpTSConfig
14249  *        write out a single text search configuration
14250  */
14251 static void
14252 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14253 {
14254         DumpOptions *dopt = fout->dopt;
14255         PQExpBuffer q;
14256         PQExpBuffer delq;
14257         PQExpBuffer query;
14258         char       *qcfgname;
14259         PGresult   *res;
14260         char       *nspname;
14261         char       *prsname;
14262         int                     ntups,
14263                                 i;
14264         int                     i_tokenname;
14265         int                     i_dictname;
14266
14267         /* Skip if not to be dumped */
14268         if (!cfginfo->dobj.dump || dopt->dataOnly)
14269                 return;
14270
14271         q = createPQExpBuffer();
14272         delq = createPQExpBuffer();
14273         query = createPQExpBuffer();
14274
14275         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14276
14277         /* Fetch name and namespace of the config's parser */
14278         appendPQExpBuffer(query, "SELECT nspname, prsname "
14279                                           "FROM pg_ts_parser p, pg_namespace n "
14280                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14281                                           cfginfo->cfgparser);
14282         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14283         nspname = PQgetvalue(res, 0, 0);
14284         prsname = PQgetvalue(res, 0, 1);
14285
14286         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14287                                           fmtQualifiedDumpable(cfginfo));
14288
14289         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14290         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14291
14292         PQclear(res);
14293
14294         resetPQExpBuffer(query);
14295         appendPQExpBuffer(query,
14296                                           "SELECT\n"
14297                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14298                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14299                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14300                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14301                                           "WHERE m.mapcfg = '%u'\n"
14302                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14303                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14304
14305         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14306         ntups = PQntuples(res);
14307
14308         i_tokenname = PQfnumber(res, "tokenname");
14309         i_dictname = PQfnumber(res, "dictname");
14310
14311         for (i = 0; i < ntups; i++)
14312         {
14313                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14314                 char       *dictname = PQgetvalue(res, i, i_dictname);
14315
14316                 if (i == 0 ||
14317                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14318                 {
14319                         /* starting a new token type, so start a new command */
14320                         if (i > 0)
14321                                 appendPQExpBufferStr(q, ";\n");
14322                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14323                                                           fmtQualifiedDumpable(cfginfo));
14324                         /* tokenname needs quoting, dictname does NOT */
14325                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14326                                                           fmtId(tokenname), dictname);
14327                 }
14328                 else
14329                         appendPQExpBuffer(q, ", %s", dictname);
14330         }
14331
14332         if (ntups > 0)
14333                 appendPQExpBufferStr(q, ";\n");
14334
14335         PQclear(res);
14336
14337         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14338                                           fmtQualifiedDumpable(cfginfo));
14339
14340         if (dopt->binary_upgrade)
14341                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14342                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14343                                                                                 cfginfo->dobj.namespace->dobj.name);
14344
14345         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14346                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14347                                          cfginfo->dobj.name,
14348                                          cfginfo->dobj.namespace->dobj.name,
14349                                          NULL,
14350                                          cfginfo->rolname,
14351                                          false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14352                                          q->data, delq->data, NULL,
14353                                          NULL, 0,
14354                                          NULL, NULL);
14355
14356         /* Dump Configuration Comments */
14357         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14358                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14359                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14360                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14361
14362         destroyPQExpBuffer(q);
14363         destroyPQExpBuffer(delq);
14364         destroyPQExpBuffer(query);
14365         free(qcfgname);
14366 }
14367
14368 /*
14369  * dumpForeignDataWrapper
14370  *        write out a single foreign-data wrapper definition
14371  */
14372 static void
14373 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14374 {
14375         DumpOptions *dopt = fout->dopt;
14376         PQExpBuffer q;
14377         PQExpBuffer delq;
14378         char       *qfdwname;
14379
14380         /* Skip if not to be dumped */
14381         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14382                 return;
14383
14384         q = createPQExpBuffer();
14385         delq = createPQExpBuffer();
14386
14387         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14388
14389         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14390                                           qfdwname);
14391
14392         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14393                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14394
14395         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14396                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14397
14398         if (strlen(fdwinfo->fdwoptions) > 0)
14399                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14400
14401         appendPQExpBufferStr(q, ";\n");
14402
14403         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14404                                           qfdwname);
14405
14406         if (dopt->binary_upgrade)
14407                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14408                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14409                                                                                 NULL);
14410
14411         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14412                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14413                                          fdwinfo->dobj.name,
14414                                          NULL,
14415                                          NULL,
14416                                          fdwinfo->rolname,
14417                                          false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14418                                          q->data, delq->data, NULL,
14419                                          NULL, 0,
14420                                          NULL, NULL);
14421
14422         /* Dump Foreign Data Wrapper Comments */
14423         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14424                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14425                                         NULL, fdwinfo->rolname,
14426                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14427
14428         /* Handle the ACL */
14429         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14430                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14431                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14432                                 NULL, fdwinfo->rolname,
14433                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14434                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14435
14436         free(qfdwname);
14437
14438         destroyPQExpBuffer(q);
14439         destroyPQExpBuffer(delq);
14440 }
14441
14442 /*
14443  * dumpForeignServer
14444  *        write out a foreign server definition
14445  */
14446 static void
14447 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14448 {
14449         DumpOptions *dopt = fout->dopt;
14450         PQExpBuffer q;
14451         PQExpBuffer delq;
14452         PQExpBuffer query;
14453         PGresult   *res;
14454         char       *qsrvname;
14455         char       *fdwname;
14456
14457         /* Skip if not to be dumped */
14458         if (!srvinfo->dobj.dump || dopt->dataOnly)
14459                 return;
14460
14461         q = createPQExpBuffer();
14462         delq = createPQExpBuffer();
14463         query = createPQExpBuffer();
14464
14465         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14466
14467         /* look up the foreign-data wrapper */
14468         appendPQExpBuffer(query, "SELECT fdwname "
14469                                           "FROM pg_foreign_data_wrapper w "
14470                                           "WHERE w.oid = '%u'",
14471                                           srvinfo->srvfdw);
14472         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14473         fdwname = PQgetvalue(res, 0, 0);
14474
14475         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14476         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14477         {
14478                 appendPQExpBufferStr(q, " TYPE ");
14479                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14480         }
14481         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14482         {
14483                 appendPQExpBufferStr(q, " VERSION ");
14484                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14485         }
14486
14487         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14488         appendPQExpBufferStr(q, fmtId(fdwname));
14489
14490         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14491                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14492
14493         appendPQExpBufferStr(q, ";\n");
14494
14495         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14496                                           qsrvname);
14497
14498         if (dopt->binary_upgrade)
14499                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14500                                                                                 "SERVER", qsrvname, NULL);
14501
14502         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14503                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14504                                          srvinfo->dobj.name,
14505                                          NULL,
14506                                          NULL,
14507                                          srvinfo->rolname,
14508                                          false, "SERVER", SECTION_PRE_DATA,
14509                                          q->data, delq->data, NULL,
14510                                          NULL, 0,
14511                                          NULL, NULL);
14512
14513         /* Dump Foreign Server Comments */
14514         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14515                 dumpComment(fout, "SERVER", qsrvname,
14516                                         NULL, srvinfo->rolname,
14517                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14518
14519         /* Handle the ACL */
14520         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14521                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14522                                 "FOREIGN SERVER", qsrvname, NULL,
14523                                 NULL, srvinfo->rolname,
14524                                 srvinfo->srvacl, srvinfo->rsrvacl,
14525                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14526
14527         /* Dump user mappings */
14528         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14529                 dumpUserMappings(fout,
14530                                                  srvinfo->dobj.name, NULL,
14531                                                  srvinfo->rolname,
14532                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14533
14534         free(qsrvname);
14535
14536         destroyPQExpBuffer(q);
14537         destroyPQExpBuffer(delq);
14538         destroyPQExpBuffer(query);
14539 }
14540
14541 /*
14542  * dumpUserMappings
14543  *
14544  * This routine is used to dump any user mappings associated with the
14545  * server handed to this routine. Should be called after ArchiveEntry()
14546  * for the server.
14547  */
14548 static void
14549 dumpUserMappings(Archive *fout,
14550                                  const char *servername, const char *namespace,
14551                                  const char *owner,
14552                                  CatalogId catalogId, DumpId dumpId)
14553 {
14554         PQExpBuffer q;
14555         PQExpBuffer delq;
14556         PQExpBuffer query;
14557         PQExpBuffer tag;
14558         PGresult   *res;
14559         int                     ntups;
14560         int                     i_usename;
14561         int                     i_umoptions;
14562         int                     i;
14563
14564         q = createPQExpBuffer();
14565         tag = createPQExpBuffer();
14566         delq = createPQExpBuffer();
14567         query = createPQExpBuffer();
14568
14569         /*
14570          * We read from the publicly accessible view pg_user_mappings, so as not
14571          * to fail if run by a non-superuser.  Note that the view will show
14572          * umoptions as null if the user hasn't got privileges for the associated
14573          * server; this means that pg_dump will dump such a mapping, but with no
14574          * OPTIONS clause.  A possible alternative is to skip such mappings
14575          * altogether, but it's not clear that that's an improvement.
14576          */
14577         appendPQExpBuffer(query,
14578                                           "SELECT usename, "
14579                                           "array_to_string(ARRAY("
14580                                           "SELECT quote_ident(option_name) || ' ' || "
14581                                           "quote_literal(option_value) "
14582                                           "FROM pg_options_to_table(umoptions) "
14583                                           "ORDER BY option_name"
14584                                           "), E',\n    ') AS umoptions "
14585                                           "FROM pg_user_mappings "
14586                                           "WHERE srvid = '%u' "
14587                                           "ORDER BY usename",
14588                                           catalogId.oid);
14589
14590         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14591
14592         ntups = PQntuples(res);
14593         i_usename = PQfnumber(res, "usename");
14594         i_umoptions = PQfnumber(res, "umoptions");
14595
14596         for (i = 0; i < ntups; i++)
14597         {
14598                 char       *usename;
14599                 char       *umoptions;
14600
14601                 usename = PQgetvalue(res, i, i_usename);
14602                 umoptions = PQgetvalue(res, i, i_umoptions);
14603
14604                 resetPQExpBuffer(q);
14605                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14606                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14607
14608                 if (umoptions && strlen(umoptions) > 0)
14609                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14610
14611                 appendPQExpBufferStr(q, ";\n");
14612
14613                 resetPQExpBuffer(delq);
14614                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14615                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14616
14617                 resetPQExpBuffer(tag);
14618                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14619                                                   usename, servername);
14620
14621                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14622                                          tag->data,
14623                                          namespace,
14624                                          NULL,
14625                                          owner, false,
14626                                          "USER MAPPING", SECTION_PRE_DATA,
14627                                          q->data, delq->data, NULL,
14628                                          &dumpId, 1,
14629                                          NULL, NULL);
14630         }
14631
14632         PQclear(res);
14633
14634         destroyPQExpBuffer(query);
14635         destroyPQExpBuffer(delq);
14636         destroyPQExpBuffer(tag);
14637         destroyPQExpBuffer(q);
14638 }
14639
14640 /*
14641  * Write out default privileges information
14642  */
14643 static void
14644 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14645 {
14646         DumpOptions *dopt = fout->dopt;
14647         PQExpBuffer q;
14648         PQExpBuffer tag;
14649         const char *type;
14650
14651         /* Skip if not to be dumped */
14652         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14653                 return;
14654
14655         q = createPQExpBuffer();
14656         tag = createPQExpBuffer();
14657
14658         switch (daclinfo->defaclobjtype)
14659         {
14660                 case DEFACLOBJ_RELATION:
14661                         type = "TABLES";
14662                         break;
14663                 case DEFACLOBJ_SEQUENCE:
14664                         type = "SEQUENCES";
14665                         break;
14666                 case DEFACLOBJ_FUNCTION:
14667                         type = "FUNCTIONS";
14668                         break;
14669                 case DEFACLOBJ_TYPE:
14670                         type = "TYPES";
14671                         break;
14672                 case DEFACLOBJ_NAMESPACE:
14673                         type = "SCHEMAS";
14674                         break;
14675                 default:
14676                         /* shouldn't get here */
14677                         exit_horribly(NULL,
14678                                                   "unrecognized object type in default privileges: %d\n",
14679                                                   (int) daclinfo->defaclobjtype);
14680                         type = "";                      /* keep compiler quiet */
14681         }
14682
14683         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14684
14685         /* build the actual command(s) for this tuple */
14686         if (!buildDefaultACLCommands(type,
14687                                                                  daclinfo->dobj.namespace != NULL ?
14688                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14689                                                                  daclinfo->defaclacl,
14690                                                                  daclinfo->rdefaclacl,
14691                                                                  daclinfo->initdefaclacl,
14692                                                                  daclinfo->initrdefaclacl,
14693                                                                  daclinfo->defaclrole,
14694                                                                  fout->remoteVersion,
14695                                                                  q))
14696                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14697                                           daclinfo->defaclacl);
14698
14699         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14700                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14701                                          tag->data,
14702                                          daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14703                                          NULL,
14704                                          daclinfo->defaclrole,
14705                                          false, "DEFAULT ACL", SECTION_POST_DATA,
14706                                          q->data, "", NULL,
14707                                          NULL, 0,
14708                                          NULL, NULL);
14709
14710         destroyPQExpBuffer(tag);
14711         destroyPQExpBuffer(q);
14712 }
14713
14714 /*----------
14715  * Write out grant/revoke information
14716  *
14717  * 'objCatId' is the catalog ID of the underlying object.
14718  * 'objDumpId' is the dump ID of the underlying object.
14719  * 'type' must be one of
14720  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14721  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14722  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14723  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14724  *              (Currently we assume that subname is only provided for table columns.)
14725  * 'nspname' is the namespace the object is in (NULL if none).
14726  * 'owner' is the owner, NULL if there is no owner (for languages).
14727  * 'acls' contains the ACL string of the object from the appropriate system
14728  *              catalog field; it will be passed to buildACLCommands for building the
14729  *              appropriate GRANT commands.
14730  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14731  *              object; it will be passed to buildACLCommands for building the
14732  *              appropriate REVOKE commands.
14733  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14734  *              privileges, to be recorded into pg_init_privs
14735  * 'initracls' In binary-upgrade mode, ACL string of the object's
14736  *              revoked-from-default privileges, to be recorded into pg_init_privs
14737  *
14738  * NB: initacls/initracls are needed because extensions can set privileges on
14739  * an object during the extension's script file and we record those into
14740  * pg_init_privs as that object's initial privileges.
14741  *----------
14742  */
14743 static void
14744 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14745                 const char *type, const char *name, const char *subname,
14746                 const char *nspname, const char *owner,
14747                 const char *acls, const char *racls,
14748                 const char *initacls, const char *initracls)
14749 {
14750         DumpOptions *dopt = fout->dopt;
14751         PQExpBuffer sql;
14752
14753         /* Do nothing if ACL dump is not enabled */
14754         if (dopt->aclsSkip)
14755                 return;
14756
14757         /* --data-only skips ACLs *except* BLOB ACLs */
14758         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14759                 return;
14760
14761         sql = createPQExpBuffer();
14762
14763         /*
14764          * Check to see if this object has had any initial ACLs included for it.
14765          * If so, we are in binary upgrade mode and these are the ACLs to turn
14766          * into GRANT and REVOKE statements to set and record the initial
14767          * privileges for an extension object.  Let the backend know that these
14768          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14769          * before and after.
14770          */
14771         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14772         {
14773                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14774                 if (!buildACLCommands(name, subname, nspname, type,
14775                                                           initacls, initracls, owner,
14776                                                           "", fout->remoteVersion, sql))
14777                         exit_horribly(NULL,
14778                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14779                                                   initacls, initracls, name, type);
14780                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14781         }
14782
14783         if (!buildACLCommands(name, subname, nspname, type,
14784                                                   acls, racls, owner,
14785                                                   "", fout->remoteVersion, sql))
14786                 exit_horribly(NULL,
14787                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14788                                           acls, racls, name, type);
14789
14790         if (sql->len > 0)
14791         {
14792                 PQExpBuffer tag = createPQExpBuffer();
14793
14794                 if (subname)
14795                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14796                 else
14797                         appendPQExpBuffer(tag, "%s %s", type, name);
14798
14799                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14800                                          tag->data, nspname,
14801                                          NULL,
14802                                          owner ? owner : "",
14803                                          false, "ACL", SECTION_NONE,
14804                                          sql->data, "", NULL,
14805                                          &(objDumpId), 1,
14806                                          NULL, NULL);
14807                 destroyPQExpBuffer(tag);
14808         }
14809
14810         destroyPQExpBuffer(sql);
14811 }
14812
14813 /*
14814  * dumpSecLabel
14815  *
14816  * This routine is used to dump any security labels associated with the
14817  * object handed to this routine. The routine takes the object type
14818  * and object name (ready to print, except for schema decoration), plus
14819  * the namespace and owner of the object (for labeling the ArchiveEntry),
14820  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14821  * plus the dump ID for the object (for setting a dependency).
14822  * If a matching pg_seclabel entry is found, it is dumped.
14823  *
14824  * Note: although this routine takes a dumpId for dependency purposes,
14825  * that purpose is just to mark the dependency in the emitted dump file
14826  * for possible future use by pg_restore.  We do NOT use it for determining
14827  * ordering of the label in the dump file, because this routine is called
14828  * after dependency sorting occurs.  This routine should be called just after
14829  * calling ArchiveEntry() for the specified object.
14830  */
14831 static void
14832 dumpSecLabel(Archive *fout, const char *type, const char *name,
14833                          const char *namespace, const char *owner,
14834                          CatalogId catalogId, int subid, DumpId dumpId)
14835 {
14836         DumpOptions *dopt = fout->dopt;
14837         SecLabelItem *labels;
14838         int                     nlabels;
14839         int                     i;
14840         PQExpBuffer query;
14841
14842         /* do nothing, if --no-security-labels is supplied */
14843         if (dopt->no_security_labels)
14844                 return;
14845
14846         /* Security labels are schema not data ... except blob labels are data */
14847         if (strcmp(type, "LARGE OBJECT") != 0)
14848         {
14849                 if (dopt->dataOnly)
14850                         return;
14851         }
14852         else
14853         {
14854                 /* We do dump blob security labels in binary-upgrade mode */
14855                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14856                         return;
14857         }
14858
14859         /* Search for security labels associated with catalogId, using table */
14860         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14861
14862         query = createPQExpBuffer();
14863
14864         for (i = 0; i < nlabels; i++)
14865         {
14866                 /*
14867                  * Ignore label entries for which the subid doesn't match.
14868                  */
14869                 if (labels[i].objsubid != subid)
14870                         continue;
14871
14872                 appendPQExpBuffer(query,
14873                                                   "SECURITY LABEL FOR %s ON %s ",
14874                                                   fmtId(labels[i].provider), type);
14875                 if (namespace && *namespace)
14876                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14877                 appendPQExpBuffer(query, "%s IS ", name);
14878                 appendStringLiteralAH(query, labels[i].label, fout);
14879                 appendPQExpBufferStr(query, ";\n");
14880         }
14881
14882         if (query->len > 0)
14883         {
14884                 PQExpBuffer tag = createPQExpBuffer();
14885
14886                 appendPQExpBuffer(tag, "%s %s", type, name);
14887                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14888                                          tag->data, namespace, NULL, owner,
14889                                          false, "SECURITY LABEL", SECTION_NONE,
14890                                          query->data, "", NULL,
14891                                          &(dumpId), 1,
14892                                          NULL, NULL);
14893                 destroyPQExpBuffer(tag);
14894         }
14895
14896         destroyPQExpBuffer(query);
14897 }
14898
14899 /*
14900  * dumpTableSecLabel
14901  *
14902  * As above, but dump security label for both the specified table (or view)
14903  * and its columns.
14904  */
14905 static void
14906 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14907 {
14908         DumpOptions *dopt = fout->dopt;
14909         SecLabelItem *labels;
14910         int                     nlabels;
14911         int                     i;
14912         PQExpBuffer query;
14913         PQExpBuffer target;
14914
14915         /* do nothing, if --no-security-labels is supplied */
14916         if (dopt->no_security_labels)
14917                 return;
14918
14919         /* SecLabel are SCHEMA not data */
14920         if (dopt->dataOnly)
14921                 return;
14922
14923         /* Search for comments associated with relation, using table */
14924         nlabels = findSecLabels(fout,
14925                                                         tbinfo->dobj.catId.tableoid,
14926                                                         tbinfo->dobj.catId.oid,
14927                                                         &labels);
14928
14929         /* If security labels exist, build SECURITY LABEL statements */
14930         if (nlabels <= 0)
14931                 return;
14932
14933         query = createPQExpBuffer();
14934         target = createPQExpBuffer();
14935
14936         for (i = 0; i < nlabels; i++)
14937         {
14938                 const char *colname;
14939                 const char *provider = labels[i].provider;
14940                 const char *label = labels[i].label;
14941                 int                     objsubid = labels[i].objsubid;
14942
14943                 resetPQExpBuffer(target);
14944                 if (objsubid == 0)
14945                 {
14946                         appendPQExpBuffer(target, "%s %s", reltypename,
14947                                                           fmtQualifiedDumpable(tbinfo));
14948                 }
14949                 else
14950                 {
14951                         colname = getAttrName(objsubid, tbinfo);
14952                         /* first fmtXXX result must be consumed before calling again */
14953                         appendPQExpBuffer(target, "COLUMN %s",
14954                                                           fmtQualifiedDumpable(tbinfo));
14955                         appendPQExpBuffer(target, ".%s", fmtId(colname));
14956                 }
14957                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14958                                                   fmtId(provider), target->data);
14959                 appendStringLiteralAH(query, label, fout);
14960                 appendPQExpBufferStr(query, ";\n");
14961         }
14962         if (query->len > 0)
14963         {
14964                 resetPQExpBuffer(target);
14965                 appendPQExpBuffer(target, "%s %s", reltypename,
14966                                                   fmtId(tbinfo->dobj.name));
14967                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14968                                          target->data,
14969                                          tbinfo->dobj.namespace->dobj.name,
14970                                          NULL, tbinfo->rolname,
14971                                          false, "SECURITY LABEL", SECTION_NONE,
14972                                          query->data, "", NULL,
14973                                          &(tbinfo->dobj.dumpId), 1,
14974                                          NULL, NULL);
14975         }
14976         destroyPQExpBuffer(query);
14977         destroyPQExpBuffer(target);
14978 }
14979
14980 /*
14981  * findSecLabels
14982  *
14983  * Find the security label(s), if any, associated with the given object.
14984  * All the objsubid values associated with the given classoid/objoid are
14985  * found with one search.
14986  */
14987 static int
14988 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14989 {
14990         /* static storage for table of security labels */
14991         static SecLabelItem *labels = NULL;
14992         static int      nlabels = -1;
14993
14994         SecLabelItem *middle = NULL;
14995         SecLabelItem *low;
14996         SecLabelItem *high;
14997         int                     nmatch;
14998
14999         /* Get security labels if we didn't already */
15000         if (nlabels < 0)
15001                 nlabels = collectSecLabels(fout, &labels);
15002
15003         if (nlabels <= 0)                       /* no labels, so no match is possible */
15004         {
15005                 *items = NULL;
15006                 return 0;
15007         }
15008
15009         /*
15010          * Do binary search to find some item matching the object.
15011          */
15012         low = &labels[0];
15013         high = &labels[nlabels - 1];
15014         while (low <= high)
15015         {
15016                 middle = low + (high - low) / 2;
15017
15018                 if (classoid < middle->classoid)
15019                         high = middle - 1;
15020                 else if (classoid > middle->classoid)
15021                         low = middle + 1;
15022                 else if (objoid < middle->objoid)
15023                         high = middle - 1;
15024                 else if (objoid > middle->objoid)
15025                         low = middle + 1;
15026                 else
15027                         break;                          /* found a match */
15028         }
15029
15030         if (low > high)                         /* no matches */
15031         {
15032                 *items = NULL;
15033                 return 0;
15034         }
15035
15036         /*
15037          * Now determine how many items match the object.  The search loop
15038          * invariant still holds: only items between low and high inclusive could
15039          * match.
15040          */
15041         nmatch = 1;
15042         while (middle > low)
15043         {
15044                 if (classoid != middle[-1].classoid ||
15045                         objoid != middle[-1].objoid)
15046                         break;
15047                 middle--;
15048                 nmatch++;
15049         }
15050
15051         *items = middle;
15052
15053         middle += nmatch;
15054         while (middle <= high)
15055         {
15056                 if (classoid != middle->classoid ||
15057                         objoid != middle->objoid)
15058                         break;
15059                 middle++;
15060                 nmatch++;
15061         }
15062
15063         return nmatch;
15064 }
15065
15066 /*
15067  * collectSecLabels
15068  *
15069  * Construct a table of all security labels available for database objects.
15070  * It's much faster to pull them all at once.
15071  *
15072  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15073  */
15074 static int
15075 collectSecLabels(Archive *fout, SecLabelItem **items)
15076 {
15077         PGresult   *res;
15078         PQExpBuffer query;
15079         int                     i_label;
15080         int                     i_provider;
15081         int                     i_classoid;
15082         int                     i_objoid;
15083         int                     i_objsubid;
15084         int                     ntups;
15085         int                     i;
15086         SecLabelItem *labels;
15087
15088         query = createPQExpBuffer();
15089
15090         appendPQExpBufferStr(query,
15091                                                  "SELECT label, provider, classoid, objoid, objsubid "
15092                                                  "FROM pg_catalog.pg_seclabel "
15093                                                  "ORDER BY classoid, objoid, objsubid");
15094
15095         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15096
15097         /* Construct lookup table containing OIDs in numeric form */
15098         i_label = PQfnumber(res, "label");
15099         i_provider = PQfnumber(res, "provider");
15100         i_classoid = PQfnumber(res, "classoid");
15101         i_objoid = PQfnumber(res, "objoid");
15102         i_objsubid = PQfnumber(res, "objsubid");
15103
15104         ntups = PQntuples(res);
15105
15106         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15107
15108         for (i = 0; i < ntups; i++)
15109         {
15110                 labels[i].label = PQgetvalue(res, i, i_label);
15111                 labels[i].provider = PQgetvalue(res, i, i_provider);
15112                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15113                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15114                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15115         }
15116
15117         /* Do NOT free the PGresult since we are keeping pointers into it */
15118         destroyPQExpBuffer(query);
15119
15120         *items = labels;
15121         return ntups;
15122 }
15123
15124 /*
15125  * dumpTable
15126  *        write out to fout the declarations (not data) of a user-defined table
15127  */
15128 static void
15129 dumpTable(Archive *fout, TableInfo *tbinfo)
15130 {
15131         DumpOptions *dopt = fout->dopt;
15132         char       *namecopy;
15133
15134         /*
15135          * noop if we are not dumping anything about this table, or if we are
15136          * doing a data-only dump
15137          */
15138         if (!tbinfo->dobj.dump || dopt->dataOnly)
15139                 return;
15140
15141         if (tbinfo->relkind == RELKIND_SEQUENCE)
15142                 dumpSequence(fout, tbinfo);
15143         else
15144                 dumpTableSchema(fout, tbinfo);
15145
15146         /* Handle the ACL here */
15147         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15148         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15149         {
15150                 const char *objtype =
15151                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15152
15153                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15154                                 objtype, namecopy, NULL,
15155                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15156                                 tbinfo->relacl, tbinfo->rrelacl,
15157                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15158         }
15159
15160         /*
15161          * Handle column ACLs, if any.  Note: we pull these with a separate query
15162          * rather than trying to fetch them during getTableAttrs, so that we won't
15163          * miss ACLs on system columns.
15164          */
15165         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15166         {
15167                 PQExpBuffer query = createPQExpBuffer();
15168                 PGresult   *res;
15169                 int                     i;
15170
15171                 if (fout->remoteVersion >= 90600)
15172                 {
15173                         PQExpBuffer acl_subquery = createPQExpBuffer();
15174                         PQExpBuffer racl_subquery = createPQExpBuffer();
15175                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15176                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15177
15178                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15179                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15180                                                         dopt->binary_upgrade);
15181
15182                         appendPQExpBuffer(query,
15183                                                           "SELECT at.attname, "
15184                                                           "%s AS attacl, "
15185                                                           "%s AS rattacl, "
15186                                                           "%s AS initattacl, "
15187                                                           "%s AS initrattacl "
15188                                                           "FROM pg_catalog.pg_attribute at "
15189                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15190                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15191                                                           "(at.attrelid = pip.objoid "
15192                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15193                                                           "AND at.attnum = pip.objsubid) "
15194                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15195                                                           "NOT at.attisdropped "
15196                                                           "AND ("
15197                                                           "%s IS NOT NULL OR "
15198                                                           "%s IS NOT NULL OR "
15199                                                           "%s IS NOT NULL OR "
15200                                                           "%s IS NOT NULL)"
15201                                                           "ORDER BY at.attnum",
15202                                                           acl_subquery->data,
15203                                                           racl_subquery->data,
15204                                                           initacl_subquery->data,
15205                                                           initracl_subquery->data,
15206                                                           tbinfo->dobj.catId.oid,
15207                                                           acl_subquery->data,
15208                                                           racl_subquery->data,
15209                                                           initacl_subquery->data,
15210                                                           initracl_subquery->data);
15211
15212                         destroyPQExpBuffer(acl_subquery);
15213                         destroyPQExpBuffer(racl_subquery);
15214                         destroyPQExpBuffer(initacl_subquery);
15215                         destroyPQExpBuffer(initracl_subquery);
15216                 }
15217                 else
15218                 {
15219                         appendPQExpBuffer(query,
15220                                                           "SELECT attname, attacl, NULL as rattacl, "
15221                                                           "NULL AS initattacl, NULL AS initrattacl "
15222                                                           "FROM pg_catalog.pg_attribute "
15223                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15224                                                           "AND attacl IS NOT NULL "
15225                                                           "ORDER BY attnum",
15226                                                           tbinfo->dobj.catId.oid);
15227                 }
15228
15229                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15230
15231                 for (i = 0; i < PQntuples(res); i++)
15232                 {
15233                         char       *attname = PQgetvalue(res, i, 0);
15234                         char       *attacl = PQgetvalue(res, i, 1);
15235                         char       *rattacl = PQgetvalue(res, i, 2);
15236                         char       *initattacl = PQgetvalue(res, i, 3);
15237                         char       *initrattacl = PQgetvalue(res, i, 4);
15238                         char       *attnamecopy;
15239
15240                         attnamecopy = pg_strdup(fmtId(attname));
15241                         /* Column's GRANT type is always TABLE */
15242                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15243                                         "TABLE", namecopy, attnamecopy,
15244                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15245                                         attacl, rattacl, initattacl, initrattacl);
15246                         free(attnamecopy);
15247                 }
15248                 PQclear(res);
15249                 destroyPQExpBuffer(query);
15250         }
15251
15252         free(namecopy);
15253
15254         return;
15255 }
15256
15257 /*
15258  * Create the AS clause for a view or materialized view. The semicolon is
15259  * stripped because a materialized view must add a WITH NO DATA clause.
15260  *
15261  * This returns a new buffer which must be freed by the caller.
15262  */
15263 static PQExpBuffer
15264 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15265 {
15266         PQExpBuffer query = createPQExpBuffer();
15267         PQExpBuffer result = createPQExpBuffer();
15268         PGresult   *res;
15269         int                     len;
15270
15271         /* Fetch the view definition */
15272         appendPQExpBuffer(query,
15273                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15274                                           tbinfo->dobj.catId.oid);
15275
15276         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15277
15278         if (PQntuples(res) != 1)
15279         {
15280                 if (PQntuples(res) < 1)
15281                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15282                                                   tbinfo->dobj.name);
15283                 else
15284                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15285                                                   tbinfo->dobj.name);
15286         }
15287
15288         len = PQgetlength(res, 0, 0);
15289
15290         if (len == 0)
15291                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15292                                           tbinfo->dobj.name);
15293
15294         /* Strip off the trailing semicolon so that other things may follow. */
15295         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15296         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15297
15298         PQclear(res);
15299         destroyPQExpBuffer(query);
15300
15301         return result;
15302 }
15303
15304 /*
15305  * Create a dummy AS clause for a view.  This is used when the real view
15306  * definition has to be postponed because of circular dependencies.
15307  * We must duplicate the view's external properties -- column names and types
15308  * (including collation) -- so that it works for subsequent references.
15309  *
15310  * This returns a new buffer which must be freed by the caller.
15311  */
15312 static PQExpBuffer
15313 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15314 {
15315         PQExpBuffer result = createPQExpBuffer();
15316         int                     j;
15317
15318         appendPQExpBufferStr(result, "SELECT");
15319
15320         for (j = 0; j < tbinfo->numatts; j++)
15321         {
15322                 if (j > 0)
15323                         appendPQExpBufferChar(result, ',');
15324                 appendPQExpBufferStr(result, "\n    ");
15325
15326                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15327
15328                 /*
15329                  * Must add collation if not default for the type, because CREATE OR
15330                  * REPLACE VIEW won't change it
15331                  */
15332                 if (OidIsValid(tbinfo->attcollation[j]))
15333                 {
15334                         CollInfo   *coll;
15335
15336                         coll = findCollationByOid(tbinfo->attcollation[j]);
15337                         if (coll)
15338                                 appendPQExpBuffer(result, " COLLATE %s",
15339                                                                   fmtQualifiedDumpable(coll));
15340                 }
15341
15342                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15343         }
15344
15345         return result;
15346 }
15347
15348 /*
15349  * dumpTableSchema
15350  *        write the declaration (not data) of one user-defined table or view
15351  */
15352 static void
15353 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15354 {
15355         DumpOptions *dopt = fout->dopt;
15356         PQExpBuffer q = createPQExpBuffer();
15357         PQExpBuffer delq = createPQExpBuffer();
15358         char       *qrelname;
15359         char       *qualrelname;
15360         int                     numParents;
15361         TableInfo **parents;
15362         int                     actual_atts;    /* number of attrs in this CREATE statement */
15363         const char *reltypename;
15364         char       *storage;
15365         char       *srvname;
15366         char       *ftoptions;
15367         int                     j,
15368                                 k;
15369
15370         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15371         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15372
15373         if (dopt->binary_upgrade)
15374                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15375                                                                                                 tbinfo->dobj.catId.oid);
15376
15377         /* Is it a table or a view? */
15378         if (tbinfo->relkind == RELKIND_VIEW)
15379         {
15380                 PQExpBuffer result;
15381
15382                 /*
15383                  * Note: keep this code in sync with the is_view case in dumpRule()
15384                  */
15385
15386                 reltypename = "VIEW";
15387
15388                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15389
15390                 if (dopt->binary_upgrade)
15391                         binary_upgrade_set_pg_class_oids(fout, q,
15392                                                                                          tbinfo->dobj.catId.oid, false);
15393
15394                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15395
15396                 if (tbinfo->dummy_view)
15397                         result = createDummyViewAsClause(fout, tbinfo);
15398                 else
15399                 {
15400                         if (nonemptyReloptions(tbinfo->reloptions))
15401                         {
15402                                 appendPQExpBufferStr(q, " WITH (");
15403                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15404                                 appendPQExpBufferChar(q, ')');
15405                         }
15406                         result = createViewAsClause(fout, tbinfo);
15407                 }
15408                 appendPQExpBuffer(q, " AS\n%s", result->data);
15409                 destroyPQExpBuffer(result);
15410
15411                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15412                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15413                 appendPQExpBufferStr(q, ";\n");
15414         }
15415         else
15416         {
15417                 switch (tbinfo->relkind)
15418                 {
15419                         case RELKIND_FOREIGN_TABLE:
15420                                 {
15421                                         PQExpBuffer query = createPQExpBuffer();
15422                                         PGresult   *res;
15423                                         int                     i_srvname;
15424                                         int                     i_ftoptions;
15425
15426                                         reltypename = "FOREIGN TABLE";
15427
15428                                         /* retrieve name of foreign server and generic options */
15429                                         appendPQExpBuffer(query,
15430                                                                           "SELECT fs.srvname, "
15431                                                                           "pg_catalog.array_to_string(ARRAY("
15432                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15433                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15434                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15435                                                                           "ORDER BY option_name"
15436                                                                           "), E',\n    ') AS ftoptions "
15437                                                                           "FROM pg_catalog.pg_foreign_table ft "
15438                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15439                                                                           "ON (fs.oid = ft.ftserver) "
15440                                                                           "WHERE ft.ftrelid = '%u'",
15441                                                                           tbinfo->dobj.catId.oid);
15442                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15443                                         i_srvname = PQfnumber(res, "srvname");
15444                                         i_ftoptions = PQfnumber(res, "ftoptions");
15445                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15446                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15447                                         PQclear(res);
15448                                         destroyPQExpBuffer(query);
15449                                         break;
15450                                 }
15451                         case RELKIND_MATVIEW:
15452                                 reltypename = "MATERIALIZED VIEW";
15453                                 srvname = NULL;
15454                                 ftoptions = NULL;
15455                                 break;
15456                         default:
15457                                 reltypename = "TABLE";
15458                                 srvname = NULL;
15459                                 ftoptions = NULL;
15460                 }
15461
15462                 numParents = tbinfo->numParents;
15463                 parents = tbinfo->parents;
15464
15465                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15466
15467                 if (dopt->binary_upgrade)
15468                         binary_upgrade_set_pg_class_oids(fout, q,
15469                                                                                          tbinfo->dobj.catId.oid, false);
15470
15471                 appendPQExpBuffer(q, "CREATE %s%s %s",
15472                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15473                                                   "UNLOGGED " : "",
15474                                                   reltypename,
15475                                                   qualrelname);
15476
15477                 /*
15478                  * Attach to type, if reloftype; except in case of a binary upgrade,
15479                  * we dump the table normally and attach it to the type afterward.
15480                  */
15481                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15482                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15483
15484                 /*
15485                  * If the table is a partition, dump it as such; except in the case of
15486                  * a binary upgrade, we dump the table normally and attach it to the
15487                  * parent afterward.
15488                  */
15489                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15490                 {
15491                         TableInfo  *parentRel = tbinfo->parents[0];
15492
15493                         /*
15494                          * With partitions, unlike inheritance, there can only be one
15495                          * parent.
15496                          */
15497                         if (tbinfo->numParents != 1)
15498                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15499                                                           tbinfo->numParents, tbinfo->dobj.name);
15500
15501                         appendPQExpBuffer(q, " PARTITION OF %s",
15502                                                           fmtQualifiedDumpable(parentRel));
15503                 }
15504
15505                 if (tbinfo->relkind != RELKIND_MATVIEW)
15506                 {
15507                         /* Dump the attributes */
15508                         actual_atts = 0;
15509                         for (j = 0; j < tbinfo->numatts; j++)
15510                         {
15511                                 /*
15512                                  * Normally, dump if it's locally defined in this table, and
15513                                  * not dropped.  But for binary upgrade, we'll dump all the
15514                                  * columns, and then fix up the dropped and nonlocal cases
15515                                  * below.
15516                                  */
15517                                 if (shouldPrintColumn(dopt, tbinfo, j))
15518                                 {
15519                                         /*
15520                                          * Default value --- suppress if to be printed separately.
15521                                          */
15522                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15523                                                                                            !tbinfo->attrdefs[j]->separate);
15524
15525                                         /*
15526                                          * Not Null constraint --- suppress if inherited, except
15527                                          * in binary-upgrade case where that won't work.
15528                                          */
15529                                         bool            has_notnull = (tbinfo->notnull[j] &&
15530                                                                                            (!tbinfo->inhNotNull[j] ||
15531                                                                                                 dopt->binary_upgrade));
15532
15533                                         /*
15534                                          * Skip column if fully defined by reloftype or the
15535                                          * partition parent.
15536                                          */
15537                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15538                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15539                                                 continue;
15540
15541                                         /* Format properly if not first attr */
15542                                         if (actual_atts == 0)
15543                                                 appendPQExpBufferStr(q, " (");
15544                                         else
15545                                                 appendPQExpBufferChar(q, ',');
15546                                         appendPQExpBufferStr(q, "\n    ");
15547                                         actual_atts++;
15548
15549                                         /* Attribute name */
15550                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15551
15552                                         if (tbinfo->attisdropped[j])
15553                                         {
15554                                                 /*
15555                                                  * ALTER TABLE DROP COLUMN clears
15556                                                  * pg_attribute.atttypid, so we will not have gotten a
15557                                                  * valid type name; insert INTEGER as a stopgap. We'll
15558                                                  * clean things up later.
15559                                                  */
15560                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15561                                                 /* Skip all the rest, too */
15562                                                 continue;
15563                                         }
15564
15565                                         /*
15566                                          * Attribute type
15567                                          *
15568                                          * In binary-upgrade mode, we always include the type. If
15569                                          * we aren't in binary-upgrade mode, then we skip the type
15570                                          * when creating a typed table ('OF type_name') or a
15571                                          * partition ('PARTITION OF'), since the type comes from
15572                                          * the parent/partitioned table.
15573                                          */
15574                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15575                                         {
15576                                                 appendPQExpBuffer(q, " %s",
15577                                                                                   tbinfo->atttypnames[j]);
15578                                         }
15579
15580                                         /* Add collation if not default for the type */
15581                                         if (OidIsValid(tbinfo->attcollation[j]))
15582                                         {
15583                                                 CollInfo   *coll;
15584
15585                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15586                                                 if (coll)
15587                                                         appendPQExpBuffer(q, " COLLATE %s",
15588                                                                                           fmtQualifiedDumpable(coll));
15589                                         }
15590
15591                                         if (has_default)
15592                                                 appendPQExpBuffer(q, " DEFAULT %s",
15593                                                                                   tbinfo->attrdefs[j]->adef_expr);
15594
15595                                         if (has_notnull)
15596                                                 appendPQExpBufferStr(q, " NOT NULL");
15597                                 }
15598                         }
15599
15600                         /*
15601                          * Add non-inherited CHECK constraints, if any.
15602                          */
15603                         for (j = 0; j < tbinfo->ncheck; j++)
15604                         {
15605                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15606
15607                                 if (constr->separate || !constr->conislocal)
15608                                         continue;
15609
15610                                 if (actual_atts == 0)
15611                                         appendPQExpBufferStr(q, " (\n    ");
15612                                 else
15613                                         appendPQExpBufferStr(q, ",\n    ");
15614
15615                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15616                                                                   fmtId(constr->dobj.name));
15617                                 appendPQExpBufferStr(q, constr->condef);
15618
15619                                 actual_atts++;
15620                         }
15621
15622                         if (actual_atts)
15623                                 appendPQExpBufferStr(q, "\n)");
15624                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15625                                            !dopt->binary_upgrade))
15626                         {
15627                                 /*
15628                                  * We must have a parenthesized attribute list, even though
15629                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15630                                  */
15631                                 appendPQExpBufferStr(q, " (\n)");
15632                         }
15633
15634                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15635                         {
15636                                 appendPQExpBufferChar(q, '\n');
15637                                 appendPQExpBufferStr(q, tbinfo->partbound);
15638                         }
15639
15640                         /* Emit the INHERITS clause, except if this is a partition. */
15641                         if (numParents > 0 &&
15642                                 !tbinfo->ispartition &&
15643                                 !dopt->binary_upgrade)
15644                         {
15645                                 appendPQExpBufferStr(q, "\nINHERITS (");
15646                                 for (k = 0; k < numParents; k++)
15647                                 {
15648                                         TableInfo  *parentRel = parents[k];
15649
15650                                         if (k > 0)
15651                                                 appendPQExpBufferStr(q, ", ");
15652                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15653                                 }
15654                                 appendPQExpBufferChar(q, ')');
15655                         }
15656
15657                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15658                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15659
15660                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15661                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15662                 }
15663
15664                 if (nonemptyReloptions(tbinfo->reloptions) ||
15665                         nonemptyReloptions(tbinfo->toast_reloptions))
15666                 {
15667                         bool            addcomma = false;
15668
15669                         appendPQExpBufferStr(q, "\nWITH (");
15670                         if (nonemptyReloptions(tbinfo->reloptions))
15671                         {
15672                                 addcomma = true;
15673                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15674                         }
15675                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15676                         {
15677                                 if (addcomma)
15678                                         appendPQExpBufferStr(q, ", ");
15679                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15680                                                                                 fout);
15681                         }
15682                         appendPQExpBufferChar(q, ')');
15683                 }
15684
15685                 /* Dump generic options if any */
15686                 if (ftoptions && ftoptions[0])
15687                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15688
15689                 /*
15690                  * For materialized views, create the AS clause just like a view. At
15691                  * this point, we always mark the view as not populated.
15692                  */
15693                 if (tbinfo->relkind == RELKIND_MATVIEW)
15694                 {
15695                         PQExpBuffer result;
15696
15697                         result = createViewAsClause(fout, tbinfo);
15698                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15699                                                           result->data);
15700                         destroyPQExpBuffer(result);
15701                 }
15702                 else
15703                         appendPQExpBufferStr(q, ";\n");
15704
15705                 /*
15706                  * in binary upgrade mode, update the catalog with any missing values
15707                  * that might be present.
15708                  */
15709                 if (dopt->binary_upgrade)
15710                 {
15711                         for (j = 0; j < tbinfo->numatts; j++)
15712                         {
15713                                 if (tbinfo->attmissingval[j][0] != '\0')
15714                                 {
15715                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15716                                         appendPQExpBufferStr(q,
15717                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15718                                         appendStringLiteralAH(q, qualrelname, fout);
15719                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15720                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15721                                         appendPQExpBufferStr(q, ",");
15722                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15723                                         appendPQExpBufferStr(q, ");\n\n");
15724                                 }
15725                         }
15726                 }
15727
15728                 /*
15729                  * To create binary-compatible heap files, we have to ensure the same
15730                  * physical column order, including dropped columns, as in the
15731                  * original.  Therefore, we create dropped columns above and drop them
15732                  * here, also updating their attlen/attalign values so that the
15733                  * dropped column can be skipped properly.  (We do not bother with
15734                  * restoring the original attbyval setting.)  Also, inheritance
15735                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15736                  * using an INHERITS clause --- the latter would possibly mess up the
15737                  * column order.  That also means we have to take care about setting
15738                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15739                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15740                  *
15741                  * We process foreign and partitioned tables here, even though they
15742                  * lack heap storage, because they can participate in inheritance
15743                  * relationships and we want this stuff to be consistent across the
15744                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15745                  * and matviews, even though they have storage, because we don't
15746                  * support altering or dropping columns in them, nor can they be part
15747                  * of inheritance trees.
15748                  */
15749                 if (dopt->binary_upgrade &&
15750                         (tbinfo->relkind == RELKIND_RELATION ||
15751                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15752                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15753                 {
15754                         for (j = 0; j < tbinfo->numatts; j++)
15755                         {
15756                                 if (tbinfo->attisdropped[j])
15757                                 {
15758                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15759                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15760                                                                           "SET attlen = %d, "
15761                                                                           "attalign = '%c', attbyval = false\n"
15762                                                                           "WHERE attname = ",
15763                                                                           tbinfo->attlen[j],
15764                                                                           tbinfo->attalign[j]);
15765                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15766                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15767                                         appendStringLiteralAH(q, qualrelname, fout);
15768                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15769
15770                                         if (tbinfo->relkind == RELKIND_RELATION ||
15771                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15772                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15773                                                                                   qualrelname);
15774                                         else
15775                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15776                                                                                   qualrelname);
15777                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15778                                                                           fmtId(tbinfo->attnames[j]));
15779                                 }
15780                                 else if (!tbinfo->attislocal[j])
15781                                 {
15782                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15783                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15784                                                                                  "SET attislocal = false\n"
15785                                                                                  "WHERE attname = ");
15786                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15787                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15788                                         appendStringLiteralAH(q, qualrelname, fout);
15789                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15790                                 }
15791                         }
15792
15793                         for (k = 0; k < tbinfo->ncheck; k++)
15794                         {
15795                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15796
15797                                 if (constr->separate || constr->conislocal)
15798                                         continue;
15799
15800                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15801                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15802                                                                   qualrelname);
15803                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15804                                                                   fmtId(constr->dobj.name));
15805                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15806                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15807                                                                          "SET conislocal = false\n"
15808                                                                          "WHERE contype = 'c' AND conname = ");
15809                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15810                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15811                                 appendStringLiteralAH(q, qualrelname, fout);
15812                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15813                         }
15814
15815                         if (numParents > 0)
15816                         {
15817                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15818                                 for (k = 0; k < numParents; k++)
15819                                 {
15820                                         TableInfo  *parentRel = parents[k];
15821
15822                                         /* In the partitioning case, we alter the parent */
15823                                         if (tbinfo->ispartition)
15824                                                 appendPQExpBuffer(q,
15825                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15826                                                                                   fmtQualifiedDumpable(parentRel));
15827                                         else
15828                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15829                                                                                   qualrelname);
15830
15831                                         /* Partition needs specifying the bounds */
15832                                         if (tbinfo->ispartition)
15833                                                 appendPQExpBuffer(q, "%s %s;\n",
15834                                                                                   qualrelname,
15835                                                                                   tbinfo->partbound);
15836                                         else
15837                                                 appendPQExpBuffer(q, "%s;\n",
15838                                                                                   fmtQualifiedDumpable(parentRel));
15839                                 }
15840                         }
15841
15842                         if (tbinfo->reloftype)
15843                         {
15844                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15845                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15846                                                                   qualrelname,
15847                                                                   tbinfo->reloftype);
15848                         }
15849                 }
15850
15851                 /*
15852                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15853                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15854                  * TOAST tables semi-independently, here we see them only as children
15855                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15856                  * child toast table is handled below.)
15857                  */
15858                 if (dopt->binary_upgrade &&
15859                         (tbinfo->relkind == RELKIND_RELATION ||
15860                          tbinfo->relkind == RELKIND_MATVIEW))
15861                 {
15862                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15863                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15864                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15865                                                           "WHERE oid = ",
15866                                                           tbinfo->frozenxid, tbinfo->minmxid);
15867                         appendStringLiteralAH(q, qualrelname, fout);
15868                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15869
15870                         if (tbinfo->toast_oid)
15871                         {
15872                                 /*
15873                                  * The toast table will have the same OID at restore, so we
15874                                  * can safely target it by OID.
15875                                  */
15876                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15877                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15878                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15879                                                                   "WHERE oid = '%u';\n",
15880                                                                   tbinfo->toast_frozenxid,
15881                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15882                         }
15883                 }
15884
15885                 /*
15886                  * In binary_upgrade mode, restore matviews' populated status by
15887                  * poking pg_class directly.  This is pretty ugly, but we can't use
15888                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15889                  * matview is not populated even though this matview is; in any case,
15890                  * we want to transfer the matview's heap storage, not run REFRESH.
15891                  */
15892                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15893                         tbinfo->relispopulated)
15894                 {
15895                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15896                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15897                                                                  "SET relispopulated = 't'\n"
15898                                                                  "WHERE oid = ");
15899                         appendStringLiteralAH(q, qualrelname, fout);
15900                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15901                 }
15902
15903                 /*
15904                  * Dump additional per-column properties that we can't handle in the
15905                  * main CREATE TABLE command.
15906                  */
15907                 for (j = 0; j < tbinfo->numatts; j++)
15908                 {
15909                         /* None of this applies to dropped columns */
15910                         if (tbinfo->attisdropped[j])
15911                                 continue;
15912
15913                         /*
15914                          * If we didn't dump the column definition explicitly above, and
15915                          * it is NOT NULL and did not inherit that property from a parent,
15916                          * we have to mark it separately.
15917                          */
15918                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
15919                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15920                         {
15921                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15922                                                                   qualrelname);
15923                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15924                                                                   fmtId(tbinfo->attnames[j]));
15925                         }
15926
15927                         /*
15928                          * Dump per-column statistics information. We only issue an ALTER
15929                          * TABLE statement if the attstattarget entry for this column is
15930                          * non-negative (i.e. it's not the default value)
15931                          */
15932                         if (tbinfo->attstattarget[j] >= 0)
15933                         {
15934                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15935                                                                   qualrelname);
15936                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15937                                                                   fmtId(tbinfo->attnames[j]));
15938                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15939                                                                   tbinfo->attstattarget[j]);
15940                         }
15941
15942                         /*
15943                          * Dump per-column storage information.  The statement is only
15944                          * dumped if the storage has been changed from the type's default.
15945                          */
15946                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15947                         {
15948                                 switch (tbinfo->attstorage[j])
15949                                 {
15950                                         case 'p':
15951                                                 storage = "PLAIN";
15952                                                 break;
15953                                         case 'e':
15954                                                 storage = "EXTERNAL";
15955                                                 break;
15956                                         case 'm':
15957                                                 storage = "MAIN";
15958                                                 break;
15959                                         case 'x':
15960                                                 storage = "EXTENDED";
15961                                                 break;
15962                                         default:
15963                                                 storage = NULL;
15964                                 }
15965
15966                                 /*
15967                                  * Only dump the statement if it's a storage type we recognize
15968                                  */
15969                                 if (storage != NULL)
15970                                 {
15971                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15972                                                                           qualrelname);
15973                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
15974                                                                           fmtId(tbinfo->attnames[j]));
15975                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
15976                                                                           storage);
15977                                 }
15978                         }
15979
15980                         /*
15981                          * Dump per-column attributes.
15982                          */
15983                         if (tbinfo->attoptions[j][0] != '\0')
15984                         {
15985                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15986                                                                   qualrelname);
15987                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15988                                                                   fmtId(tbinfo->attnames[j]));
15989                                 appendPQExpBuffer(q, "SET (%s);\n",
15990                                                                   tbinfo->attoptions[j]);
15991                         }
15992
15993                         /*
15994                          * Dump per-column fdw options.
15995                          */
15996                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15997                                 tbinfo->attfdwoptions[j][0] != '\0')
15998                         {
15999                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16000                                                                   qualrelname);
16001                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16002                                                                   fmtId(tbinfo->attnames[j]));
16003                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16004                                                                   tbinfo->attfdwoptions[j]);
16005                         }
16006                 }
16007         }
16008
16009         /*
16010          * dump properties we only have ALTER TABLE syntax for
16011          */
16012         if ((tbinfo->relkind == RELKIND_RELATION ||
16013                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16014                  tbinfo->relkind == RELKIND_MATVIEW) &&
16015                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16016         {
16017                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16018                 {
16019                         /* nothing to do, will be set when the index is dumped */
16020                 }
16021                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16022                 {
16023                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16024                                                           qualrelname);
16025                 }
16026                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16027                 {
16028                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16029                                                           qualrelname);
16030                 }
16031         }
16032
16033         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE && tbinfo->hasoids)
16034                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s SET WITH OIDS;\n",
16035                                                   qualrelname);
16036
16037         if (tbinfo->forcerowsec)
16038                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16039                                                   qualrelname);
16040
16041         if (dopt->binary_upgrade)
16042                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16043                                                                                 reltypename, qrelname,
16044                                                                                 tbinfo->dobj.namespace->dobj.name);
16045
16046         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16047                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16048                                          tbinfo->dobj.name,
16049                                          tbinfo->dobj.namespace->dobj.name,
16050                                          (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
16051                                          tbinfo->rolname,
16052                                          (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
16053                                          reltypename,
16054                                          tbinfo->postponed_def ?
16055                                          SECTION_POST_DATA : SECTION_PRE_DATA,
16056                                          q->data, delq->data, NULL,
16057                                          NULL, 0,
16058                                          NULL, NULL);
16059
16060
16061         /* Dump Table Comments */
16062         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16063                 dumpTableComment(fout, tbinfo, reltypename);
16064
16065         /* Dump Table Security Labels */
16066         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16067                 dumpTableSecLabel(fout, tbinfo, reltypename);
16068
16069         /* Dump comments on inlined table constraints */
16070         for (j = 0; j < tbinfo->ncheck; j++)
16071         {
16072                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16073
16074                 if (constr->separate || !constr->conislocal)
16075                         continue;
16076
16077                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16078                         dumpTableConstraintComment(fout, constr);
16079         }
16080
16081         destroyPQExpBuffer(q);
16082         destroyPQExpBuffer(delq);
16083         free(qrelname);
16084         free(qualrelname);
16085 }
16086
16087 /*
16088  * dumpAttrDef --- dump an attribute's default-value declaration
16089  */
16090 static void
16091 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16092 {
16093         DumpOptions *dopt = fout->dopt;
16094         TableInfo  *tbinfo = adinfo->adtable;
16095         int                     adnum = adinfo->adnum;
16096         PQExpBuffer q;
16097         PQExpBuffer delq;
16098         char       *qualrelname;
16099         char       *tag;
16100
16101         /* Skip if table definition not to be dumped */
16102         if (!tbinfo->dobj.dump || dopt->dataOnly)
16103                 return;
16104
16105         /* Skip if not "separate"; it was dumped in the table's definition */
16106         if (!adinfo->separate)
16107                 return;
16108
16109         q = createPQExpBuffer();
16110         delq = createPQExpBuffer();
16111
16112         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16113
16114         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16115                                           qualrelname);
16116         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16117                                           fmtId(tbinfo->attnames[adnum - 1]),
16118                                           adinfo->adef_expr);
16119
16120         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16121                                           qualrelname);
16122         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16123                                           fmtId(tbinfo->attnames[adnum - 1]));
16124
16125         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16126
16127         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16128                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16129                                          tag,
16130                                          tbinfo->dobj.namespace->dobj.name,
16131                                          NULL,
16132                                          tbinfo->rolname,
16133                                          false, "DEFAULT", SECTION_PRE_DATA,
16134                                          q->data, delq->data, NULL,
16135                                          NULL, 0,
16136                                          NULL, NULL);
16137
16138         free(tag);
16139         destroyPQExpBuffer(q);
16140         destroyPQExpBuffer(delq);
16141         free(qualrelname);
16142 }
16143
16144 /*
16145  * getAttrName: extract the correct name for an attribute
16146  *
16147  * The array tblInfo->attnames[] only provides names of user attributes;
16148  * if a system attribute number is supplied, we have to fake it.
16149  * We also do a little bit of bounds checking for safety's sake.
16150  */
16151 static const char *
16152 getAttrName(int attrnum, TableInfo *tblInfo)
16153 {
16154         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16155                 return tblInfo->attnames[attrnum - 1];
16156         switch (attrnum)
16157         {
16158                 case SelfItemPointerAttributeNumber:
16159                         return "ctid";
16160                 case ObjectIdAttributeNumber:
16161                         return "oid";
16162                 case MinTransactionIdAttributeNumber:
16163                         return "xmin";
16164                 case MinCommandIdAttributeNumber:
16165                         return "cmin";
16166                 case MaxTransactionIdAttributeNumber:
16167                         return "xmax";
16168                 case MaxCommandIdAttributeNumber:
16169                         return "cmax";
16170                 case TableOidAttributeNumber:
16171                         return "tableoid";
16172         }
16173         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16174                                   attrnum, tblInfo->dobj.name);
16175         return NULL;                            /* keep compiler quiet */
16176 }
16177
16178 /*
16179  * dumpIndex
16180  *        write out to fout a user-defined index
16181  */
16182 static void
16183 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16184 {
16185         DumpOptions *dopt = fout->dopt;
16186         TableInfo  *tbinfo = indxinfo->indextable;
16187         bool            is_constraint = (indxinfo->indexconstraint != 0);
16188         PQExpBuffer q;
16189         PQExpBuffer delq;
16190         char       *qindxname;
16191
16192         if (dopt->dataOnly)
16193                 return;
16194
16195         q = createPQExpBuffer();
16196         delq = createPQExpBuffer();
16197
16198         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16199
16200         /*
16201          * If there's an associated constraint, don't dump the index per se, but
16202          * do dump any comment for it.  (This is safe because dependency ordering
16203          * will have ensured the constraint is emitted first.)  Note that the
16204          * emitted comment has to be shown as depending on the constraint, not the
16205          * index, in such cases.
16206          */
16207         if (!is_constraint)
16208         {
16209                 if (dopt->binary_upgrade)
16210                         binary_upgrade_set_pg_class_oids(fout, q,
16211                                                                                          indxinfo->dobj.catId.oid, true);
16212
16213                 /* Plain secondary index */
16214                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16215
16216                 /*
16217                  * Append ALTER TABLE commands as needed to set properties that we
16218                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16219                  * similar code in dumpConstraint!
16220                  */
16221
16222                 /* If the index is clustered, we need to record that. */
16223                 if (indxinfo->indisclustered)
16224                 {
16225                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16226                                                           fmtQualifiedDumpable(tbinfo));
16227                         /* index name is not qualified in this syntax */
16228                         appendPQExpBuffer(q, " ON %s;\n",
16229                                                           qindxname);
16230                 }
16231
16232                 /* If the index defines identity, we need to record that. */
16233                 if (indxinfo->indisreplident)
16234                 {
16235                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16236                                                           fmtQualifiedDumpable(tbinfo));
16237                         /* index name is not qualified in this syntax */
16238                         appendPQExpBuffer(q, " INDEX %s;\n",
16239                                                           qindxname);
16240                 }
16241
16242                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16243                                                   fmtQualifiedDumpable(indxinfo));
16244
16245                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16246                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16247                                                  indxinfo->dobj.name,
16248                                                  tbinfo->dobj.namespace->dobj.name,
16249                                                  indxinfo->tablespace,
16250                                                  tbinfo->rolname, false,
16251                                                  "INDEX", SECTION_POST_DATA,
16252                                                  q->data, delq->data, NULL,
16253                                                  NULL, 0,
16254                                                  NULL, NULL);
16255         }
16256
16257         /* Dump Index Comments */
16258         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16259                 dumpComment(fout, "INDEX", qindxname,
16260                                         tbinfo->dobj.namespace->dobj.name,
16261                                         tbinfo->rolname,
16262                                         indxinfo->dobj.catId, 0,
16263                                         is_constraint ? indxinfo->indexconstraint :
16264                                         indxinfo->dobj.dumpId);
16265
16266         destroyPQExpBuffer(q);
16267         destroyPQExpBuffer(delq);
16268         free(qindxname);
16269 }
16270
16271 /*
16272  * dumpIndexAttach
16273  *        write out to fout a partitioned-index attachment clause
16274  */
16275 static void
16276 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16277 {
16278         if (fout->dopt->dataOnly)
16279                 return;
16280
16281         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16282         {
16283                 PQExpBuffer q = createPQExpBuffer();
16284
16285                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16286                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16287                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16288                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16289
16290                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16291                                          attachinfo->dobj.name,
16292                                          attachinfo->dobj.namespace->dobj.name,
16293                                          NULL,
16294                                          "",
16295                                          false, "INDEX ATTACH", SECTION_POST_DATA,
16296                                          q->data, "", NULL,
16297                                          NULL, 0,
16298                                          NULL, NULL);
16299
16300                 destroyPQExpBuffer(q);
16301         }
16302 }
16303
16304 /*
16305  * dumpStatisticsExt
16306  *        write out to fout an extended statistics object
16307  */
16308 static void
16309 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16310 {
16311         DumpOptions *dopt = fout->dopt;
16312         PQExpBuffer q;
16313         PQExpBuffer delq;
16314         PQExpBuffer query;
16315         char       *qstatsextname;
16316         PGresult   *res;
16317         char       *stxdef;
16318
16319         /* Skip if not to be dumped */
16320         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16321                 return;
16322
16323         q = createPQExpBuffer();
16324         delq = createPQExpBuffer();
16325         query = createPQExpBuffer();
16326
16327         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16328
16329         appendPQExpBuffer(query, "SELECT "
16330                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16331                                           statsextinfo->dobj.catId.oid);
16332
16333         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16334
16335         stxdef = PQgetvalue(res, 0, 0);
16336
16337         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16338         appendPQExpBuffer(q, "%s;\n", stxdef);
16339
16340         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16341                                           fmtQualifiedDumpable(statsextinfo));
16342
16343         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16344                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16345                                          statsextinfo->dobj.dumpId,
16346                                          statsextinfo->dobj.name,
16347                                          statsextinfo->dobj.namespace->dobj.name,
16348                                          NULL,
16349                                          statsextinfo->rolname, false,
16350                                          "STATISTICS", SECTION_POST_DATA,
16351                                          q->data, delq->data, NULL,
16352                                          NULL, 0,
16353                                          NULL, NULL);
16354
16355         /* Dump Statistics Comments */
16356         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16357                 dumpComment(fout, "STATISTICS", qstatsextname,
16358                                         statsextinfo->dobj.namespace->dobj.name,
16359                                         statsextinfo->rolname,
16360                                         statsextinfo->dobj.catId, 0,
16361                                         statsextinfo->dobj.dumpId);
16362
16363         PQclear(res);
16364         destroyPQExpBuffer(q);
16365         destroyPQExpBuffer(delq);
16366         destroyPQExpBuffer(query);
16367         free(qstatsextname);
16368 }
16369
16370 /*
16371  * dumpConstraint
16372  *        write out to fout a user-defined constraint
16373  */
16374 static void
16375 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16376 {
16377         DumpOptions *dopt = fout->dopt;
16378         TableInfo  *tbinfo = coninfo->contable;
16379         PQExpBuffer q;
16380         PQExpBuffer delq;
16381         char       *tag = NULL;
16382
16383         /* Skip if not to be dumped */
16384         if (!coninfo->dobj.dump || dopt->dataOnly)
16385                 return;
16386
16387         q = createPQExpBuffer();
16388         delq = createPQExpBuffer();
16389
16390         if (coninfo->contype == 'p' ||
16391                 coninfo->contype == 'u' ||
16392                 coninfo->contype == 'x')
16393         {
16394                 /* Index-related constraint */
16395                 IndxInfo   *indxinfo;
16396                 int                     k;
16397
16398                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16399
16400                 if (indxinfo == NULL)
16401                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16402                                                   coninfo->dobj.name);
16403
16404                 if (dopt->binary_upgrade)
16405                         binary_upgrade_set_pg_class_oids(fout, q,
16406                                                                                          indxinfo->dobj.catId.oid, true);
16407
16408                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16409                                                   fmtQualifiedDumpable(tbinfo));
16410                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16411                                                   fmtId(coninfo->dobj.name));
16412
16413                 if (coninfo->condef)
16414                 {
16415                         /* pg_get_constraintdef should have provided everything */
16416                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16417                 }
16418                 else
16419                 {
16420                         appendPQExpBuffer(q, "%s (",
16421                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16422                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16423                         {
16424                                 int                     indkey = (int) indxinfo->indkeys[k];
16425                                 const char *attname;
16426
16427                                 if (indkey == InvalidAttrNumber)
16428                                         break;
16429                                 attname = getAttrName(indkey, tbinfo);
16430
16431                                 appendPQExpBuffer(q, "%s%s",
16432                                                                   (k == 0) ? "" : ", ",
16433                                                                   fmtId(attname));
16434                         }
16435
16436                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16437                                 appendPQExpBuffer(q, ") INCLUDE (");
16438
16439                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16440                         {
16441                                 int                     indkey = (int) indxinfo->indkeys[k];
16442                                 const char *attname;
16443
16444                                 if (indkey == InvalidAttrNumber)
16445                                         break;
16446                                 attname = getAttrName(indkey, tbinfo);
16447
16448                                 appendPQExpBuffer(q, "%s%s",
16449                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16450                                                                   fmtId(attname));
16451                         }
16452
16453                         appendPQExpBufferChar(q, ')');
16454
16455                         if (nonemptyReloptions(indxinfo->indreloptions))
16456                         {
16457                                 appendPQExpBufferStr(q, " WITH (");
16458                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16459                                 appendPQExpBufferChar(q, ')');
16460                         }
16461
16462                         if (coninfo->condeferrable)
16463                         {
16464                                 appendPQExpBufferStr(q, " DEFERRABLE");
16465                                 if (coninfo->condeferred)
16466                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16467                         }
16468
16469                         appendPQExpBufferStr(q, ";\n");
16470                 }
16471
16472                 /*
16473                  * Append ALTER TABLE commands as needed to set properties that we
16474                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16475                  * similar code in dumpIndex!
16476                  */
16477
16478                 /* If the index is clustered, we need to record that. */
16479                 if (indxinfo->indisclustered)
16480                 {
16481                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16482                                                           fmtQualifiedDumpable(tbinfo));
16483                         /* index name is not qualified in this syntax */
16484                         appendPQExpBuffer(q, " ON %s;\n",
16485                                                           fmtId(indxinfo->dobj.name));
16486                 }
16487
16488                 /* If the index defines identity, we need to record that. */
16489                 if (indxinfo->indisreplident)
16490                 {
16491                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16492                                                           fmtQualifiedDumpable(tbinfo));
16493                         /* index name is not qualified in this syntax */
16494                         appendPQExpBuffer(q, " INDEX %s;\n",
16495                                                           fmtId(indxinfo->dobj.name));
16496                 }
16497
16498                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16499                                                   fmtQualifiedDumpable(tbinfo));
16500                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16501                                                   fmtId(coninfo->dobj.name));
16502
16503                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16504
16505                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16506                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16507                                                  tag,
16508                                                  tbinfo->dobj.namespace->dobj.name,
16509                                                  indxinfo->tablespace,
16510                                                  tbinfo->rolname, false,
16511                                                  "CONSTRAINT", SECTION_POST_DATA,
16512                                                  q->data, delq->data, NULL,
16513                                                  NULL, 0,
16514                                                  NULL, NULL);
16515         }
16516         else if (coninfo->contype == 'f')
16517         {
16518                 char       *only;
16519
16520                 /*
16521                  * Foreign keys on partitioned tables are always declared as
16522                  * inheriting to partitions; for all other cases, emit them as
16523                  * applying ONLY directly to the named table, because that's how they
16524                  * work for regular inherited tables.
16525                  */
16526                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16527
16528                 /*
16529                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16530                  * current table data is not processed
16531                  */
16532                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16533                                                   only, fmtQualifiedDumpable(tbinfo));
16534                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16535                                                   fmtId(coninfo->dobj.name),
16536                                                   coninfo->condef);
16537
16538                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16539                                                   only, fmtQualifiedDumpable(tbinfo));
16540                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16541                                                   fmtId(coninfo->dobj.name));
16542
16543                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16544
16545                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16546                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16547                                                  tag,
16548                                                  tbinfo->dobj.namespace->dobj.name,
16549                                                  NULL,
16550                                                  tbinfo->rolname, false,
16551                                                  "FK CONSTRAINT", SECTION_POST_DATA,
16552                                                  q->data, delq->data, NULL,
16553                                                  NULL, 0,
16554                                                  NULL, NULL);
16555         }
16556         else if (coninfo->contype == 'c' && tbinfo)
16557         {
16558                 /* CHECK constraint on a table */
16559
16560                 /* Ignore if not to be dumped separately, or if it was inherited */
16561                 if (coninfo->separate && coninfo->conislocal)
16562                 {
16563                         /* not ONLY since we want it to propagate to children */
16564                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16565                                                           fmtQualifiedDumpable(tbinfo));
16566                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16567                                                           fmtId(coninfo->dobj.name),
16568                                                           coninfo->condef);
16569
16570                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16571                                                           fmtQualifiedDumpable(tbinfo));
16572                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16573                                                           fmtId(coninfo->dobj.name));
16574
16575                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16576
16577                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16578                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16579                                                          tag,
16580                                                          tbinfo->dobj.namespace->dobj.name,
16581                                                          NULL,
16582                                                          tbinfo->rolname, false,
16583                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16584                                                          q->data, delq->data, NULL,
16585                                                          NULL, 0,
16586                                                          NULL, NULL);
16587                 }
16588         }
16589         else if (coninfo->contype == 'c' && tbinfo == NULL)
16590         {
16591                 /* CHECK constraint on a domain */
16592                 TypeInfo   *tyinfo = coninfo->condomain;
16593
16594                 /* Ignore if not to be dumped separately */
16595                 if (coninfo->separate)
16596                 {
16597                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16598                                                           fmtQualifiedDumpable(tyinfo));
16599                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16600                                                           fmtId(coninfo->dobj.name),
16601                                                           coninfo->condef);
16602
16603                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16604                                                           fmtQualifiedDumpable(tyinfo));
16605                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16606                                                           fmtId(coninfo->dobj.name));
16607
16608                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16609
16610                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16611                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16612                                                          tag,
16613                                                          tyinfo->dobj.namespace->dobj.name,
16614                                                          NULL,
16615                                                          tyinfo->rolname, false,
16616                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16617                                                          q->data, delq->data, NULL,
16618                                                          NULL, 0,
16619                                                          NULL, NULL);
16620                 }
16621         }
16622         else
16623         {
16624                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16625                                           coninfo->contype);
16626         }
16627
16628         /* Dump Constraint Comments --- only works for table constraints */
16629         if (tbinfo && coninfo->separate &&
16630                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16631                 dumpTableConstraintComment(fout, coninfo);
16632
16633         free(tag);
16634         destroyPQExpBuffer(q);
16635         destroyPQExpBuffer(delq);
16636 }
16637
16638 /*
16639  * dumpTableConstraintComment --- dump a constraint's comment if any
16640  *
16641  * This is split out because we need the function in two different places
16642  * depending on whether the constraint is dumped as part of CREATE TABLE
16643  * or as a separate ALTER command.
16644  */
16645 static void
16646 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16647 {
16648         TableInfo  *tbinfo = coninfo->contable;
16649         PQExpBuffer conprefix = createPQExpBuffer();
16650         char       *qtabname;
16651
16652         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16653
16654         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16655                                           fmtId(coninfo->dobj.name));
16656
16657         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16658                 dumpComment(fout, conprefix->data, qtabname,
16659                                         tbinfo->dobj.namespace->dobj.name,
16660                                         tbinfo->rolname,
16661                                         coninfo->dobj.catId, 0,
16662                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16663
16664         destroyPQExpBuffer(conprefix);
16665         free(qtabname);
16666 }
16667
16668 /*
16669  * findLastBuiltinOid_V71 -
16670  *
16671  * find the last built in oid
16672  *
16673  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16674  * pg_database entry for the current database.  (Note: current_database()
16675  * requires 7.3; pg_dump requires 8.0 now.)
16676  */
16677 static Oid
16678 findLastBuiltinOid_V71(Archive *fout)
16679 {
16680         PGresult   *res;
16681         Oid                     last_oid;
16682
16683         res = ExecuteSqlQueryForSingleRow(fout,
16684                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16685         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16686         PQclear(res);
16687
16688         return last_oid;
16689 }
16690
16691 /*
16692  * dumpSequence
16693  *        write the declaration (not data) of one user-defined sequence
16694  */
16695 static void
16696 dumpSequence(Archive *fout, TableInfo *tbinfo)
16697 {
16698         DumpOptions *dopt = fout->dopt;
16699         PGresult   *res;
16700         char       *startv,
16701                            *incby,
16702                            *maxv,
16703                            *minv,
16704                            *cache,
16705                            *seqtype;
16706         bool            cycled;
16707         bool            is_ascending;
16708         int64           default_minv,
16709                                 default_maxv;
16710         char            bufm[32],
16711                                 bufx[32];
16712         PQExpBuffer query = createPQExpBuffer();
16713         PQExpBuffer delqry = createPQExpBuffer();
16714         char       *qseqname;
16715
16716         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16717
16718         if (fout->remoteVersion >= 100000)
16719         {
16720                 appendPQExpBuffer(query,
16721                                                   "SELECT format_type(seqtypid, NULL), "
16722                                                   "seqstart, seqincrement, "
16723                                                   "seqmax, seqmin, "
16724                                                   "seqcache, seqcycle "
16725                                                   "FROM pg_catalog.pg_sequence "
16726                                                   "WHERE seqrelid = '%u'::oid",
16727                                                   tbinfo->dobj.catId.oid);
16728         }
16729         else if (fout->remoteVersion >= 80400)
16730         {
16731                 /*
16732                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16733                  *
16734                  * Note: it might seem that 'bigint' potentially needs to be
16735                  * schema-qualified, but actually that's a keyword.
16736                  */
16737                 appendPQExpBuffer(query,
16738                                                   "SELECT 'bigint' AS sequence_type, "
16739                                                   "start_value, increment_by, max_value, min_value, "
16740                                                   "cache_value, is_cycled FROM %s",
16741                                                   fmtQualifiedDumpable(tbinfo));
16742         }
16743         else
16744         {
16745                 appendPQExpBuffer(query,
16746                                                   "SELECT 'bigint' AS sequence_type, "
16747                                                   "0 AS start_value, increment_by, max_value, min_value, "
16748                                                   "cache_value, is_cycled FROM %s",
16749                                                   fmtQualifiedDumpable(tbinfo));
16750         }
16751
16752         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16753
16754         if (PQntuples(res) != 1)
16755         {
16756                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16757                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16758                                                                  PQntuples(res)),
16759                                   tbinfo->dobj.name, PQntuples(res));
16760                 exit_nicely(1);
16761         }
16762
16763         seqtype = PQgetvalue(res, 0, 0);
16764         startv = PQgetvalue(res, 0, 1);
16765         incby = PQgetvalue(res, 0, 2);
16766         maxv = PQgetvalue(res, 0, 3);
16767         minv = PQgetvalue(res, 0, 4);
16768         cache = PQgetvalue(res, 0, 5);
16769         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16770
16771         /* Calculate default limits for a sequence of this type */
16772         is_ascending = (incby[0] != '-');
16773         if (strcmp(seqtype, "smallint") == 0)
16774         {
16775                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16776                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16777         }
16778         else if (strcmp(seqtype, "integer") == 0)
16779         {
16780                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16781                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16782         }
16783         else if (strcmp(seqtype, "bigint") == 0)
16784         {
16785                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16786                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16787         }
16788         else
16789         {
16790                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16791                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16792         }
16793
16794         /*
16795          * 64-bit strtol() isn't very portable, so convert the limits to strings
16796          * and compare that way.
16797          */
16798         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16799         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16800
16801         /* Don't print minv/maxv if they match the respective default limit */
16802         if (strcmp(minv, bufm) == 0)
16803                 minv = NULL;
16804         if (strcmp(maxv, bufx) == 0)
16805                 maxv = NULL;
16806
16807         /*
16808          * Identity sequences are not to be dropped separately.
16809          */
16810         if (!tbinfo->is_identity_sequence)
16811         {
16812                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16813                                                   fmtQualifiedDumpable(tbinfo));
16814         }
16815
16816         resetPQExpBuffer(query);
16817
16818         if (dopt->binary_upgrade)
16819         {
16820                 binary_upgrade_set_pg_class_oids(fout, query,
16821                                                                                  tbinfo->dobj.catId.oid, false);
16822                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16823                                                                                                 tbinfo->dobj.catId.oid);
16824         }
16825
16826         if (tbinfo->is_identity_sequence)
16827         {
16828                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16829
16830                 appendPQExpBuffer(query,
16831                                                   "ALTER TABLE %s ",
16832                                                   fmtQualifiedDumpable(owning_tab));
16833                 appendPQExpBuffer(query,
16834                                                   "ALTER COLUMN %s ADD GENERATED ",
16835                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16836                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16837                         appendPQExpBuffer(query, "ALWAYS");
16838                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16839                         appendPQExpBuffer(query, "BY DEFAULT");
16840                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16841                                                   fmtQualifiedDumpable(tbinfo));
16842         }
16843         else
16844         {
16845                 appendPQExpBuffer(query,
16846                                                   "CREATE SEQUENCE %s\n",
16847                                                   fmtQualifiedDumpable(tbinfo));
16848
16849                 if (strcmp(seqtype, "bigint") != 0)
16850                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16851         }
16852
16853         if (fout->remoteVersion >= 80400)
16854                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16855
16856         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16857
16858         if (minv)
16859                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16860         else
16861                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16862
16863         if (maxv)
16864                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16865         else
16866                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16867
16868         appendPQExpBuffer(query,
16869                                           "    CACHE %s%s",
16870                                           cache, (cycled ? "\n    CYCLE" : ""));
16871
16872         if (tbinfo->is_identity_sequence)
16873                 appendPQExpBufferStr(query, "\n);\n");
16874         else
16875                 appendPQExpBufferStr(query, ";\n");
16876
16877         /* binary_upgrade:      no need to clear TOAST table oid */
16878
16879         if (dopt->binary_upgrade)
16880                 binary_upgrade_extension_member(query, &tbinfo->dobj,
16881                                                                                 "SEQUENCE", qseqname,
16882                                                                                 tbinfo->dobj.namespace->dobj.name);
16883
16884         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16885                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16886                                          tbinfo->dobj.name,
16887                                          tbinfo->dobj.namespace->dobj.name,
16888                                          NULL,
16889                                          tbinfo->rolname,
16890                                          false, "SEQUENCE", SECTION_PRE_DATA,
16891                                          query->data, delqry->data, NULL,
16892                                          NULL, 0,
16893                                          NULL, NULL);
16894
16895         /*
16896          * If the sequence is owned by a table column, emit the ALTER for it as a
16897          * separate TOC entry immediately following the sequence's own entry. It's
16898          * OK to do this rather than using full sorting logic, because the
16899          * dependency that tells us it's owned will have forced the table to be
16900          * created first.  We can't just include the ALTER in the TOC entry
16901          * because it will fail if we haven't reassigned the sequence owner to
16902          * match the table's owner.
16903          *
16904          * We need not schema-qualify the table reference because both sequence
16905          * and table must be in the same schema.
16906          */
16907         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
16908         {
16909                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16910
16911                 if (owning_tab == NULL)
16912                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
16913                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16914
16915                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16916                 {
16917                         resetPQExpBuffer(query);
16918                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16919                                                           fmtQualifiedDumpable(tbinfo));
16920                         appendPQExpBuffer(query, " OWNED BY %s",
16921                                                           fmtQualifiedDumpable(owning_tab));
16922                         appendPQExpBuffer(query, ".%s;\n",
16923                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16924
16925                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16926                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16927                                                          tbinfo->dobj.name,
16928                                                          tbinfo->dobj.namespace->dobj.name,
16929                                                          NULL,
16930                                                          tbinfo->rolname,
16931                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
16932                                                          query->data, "", NULL,
16933                                                          &(tbinfo->dobj.dumpId), 1,
16934                                                          NULL, NULL);
16935                 }
16936         }
16937
16938         /* Dump Sequence Comments and Security Labels */
16939         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16940                 dumpComment(fout, "SEQUENCE", qseqname,
16941                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16942                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16943
16944         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16945                 dumpSecLabel(fout, "SEQUENCE", qseqname,
16946                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16947                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16948
16949         PQclear(res);
16950
16951         destroyPQExpBuffer(query);
16952         destroyPQExpBuffer(delqry);
16953         free(qseqname);
16954 }
16955
16956 /*
16957  * dumpSequenceData
16958  *        write the data of one user-defined sequence
16959  */
16960 static void
16961 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16962 {
16963         TableInfo  *tbinfo = tdinfo->tdtable;
16964         PGresult   *res;
16965         char       *last;
16966         bool            called;
16967         PQExpBuffer query = createPQExpBuffer();
16968
16969         appendPQExpBuffer(query,
16970                                           "SELECT last_value, is_called FROM %s",
16971                                           fmtQualifiedDumpable(tbinfo));
16972
16973         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16974
16975         if (PQntuples(res) != 1)
16976         {
16977                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16978                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16979                                                                  PQntuples(res)),
16980                                   tbinfo->dobj.name, PQntuples(res));
16981                 exit_nicely(1);
16982         }
16983
16984         last = PQgetvalue(res, 0, 0);
16985         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
16986
16987         resetPQExpBuffer(query);
16988         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
16989         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
16990         appendPQExpBuffer(query, ", %s, %s);\n",
16991                                           last, (called ? "true" : "false"));
16992
16993         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
16994                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16995                                          tbinfo->dobj.name,
16996                                          tbinfo->dobj.namespace->dobj.name,
16997                                          NULL,
16998                                          tbinfo->rolname,
16999                                          false, "SEQUENCE SET", SECTION_DATA,
17000                                          query->data, "", NULL,
17001                                          &(tbinfo->dobj.dumpId), 1,
17002                                          NULL, NULL);
17003
17004         PQclear(res);
17005
17006         destroyPQExpBuffer(query);
17007 }
17008
17009 /*
17010  * dumpTrigger
17011  *        write the declaration of one user-defined table trigger
17012  */
17013 static void
17014 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17015 {
17016         DumpOptions *dopt = fout->dopt;
17017         TableInfo  *tbinfo = tginfo->tgtable;
17018         PQExpBuffer query;
17019         PQExpBuffer delqry;
17020         PQExpBuffer trigprefix;
17021         char       *qtabname;
17022         char       *tgargs;
17023         size_t          lentgargs;
17024         const char *p;
17025         int                     findx;
17026         char       *tag;
17027
17028         /*
17029          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17030          * created in the first place for non-dumpable triggers
17031          */
17032         if (dopt->dataOnly)
17033                 return;
17034
17035         query = createPQExpBuffer();
17036         delqry = createPQExpBuffer();
17037         trigprefix = createPQExpBuffer();
17038
17039         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17040
17041         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17042                                           fmtId(tginfo->dobj.name));
17043         appendPQExpBuffer(delqry, "ON %s;\n",
17044                                           fmtQualifiedDumpable(tbinfo));
17045
17046         if (tginfo->tgdef)
17047         {
17048                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17049         }
17050         else
17051         {
17052                 if (tginfo->tgisconstraint)
17053                 {
17054                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17055                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17056                 }
17057                 else
17058                 {
17059                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17060                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17061                 }
17062                 appendPQExpBufferStr(query, "\n    ");
17063
17064                 /* Trigger type */
17065                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17066                         appendPQExpBufferStr(query, "BEFORE");
17067                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17068                         appendPQExpBufferStr(query, "AFTER");
17069                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17070                         appendPQExpBufferStr(query, "INSTEAD OF");
17071                 else
17072                 {
17073                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17074                         exit_nicely(1);
17075                 }
17076
17077                 findx = 0;
17078                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17079                 {
17080                         appendPQExpBufferStr(query, " INSERT");
17081                         findx++;
17082                 }
17083                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17084                 {
17085                         if (findx > 0)
17086                                 appendPQExpBufferStr(query, " OR DELETE");
17087                         else
17088                                 appendPQExpBufferStr(query, " DELETE");
17089                         findx++;
17090                 }
17091                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17092                 {
17093                         if (findx > 0)
17094                                 appendPQExpBufferStr(query, " OR UPDATE");
17095                         else
17096                                 appendPQExpBufferStr(query, " UPDATE");
17097                         findx++;
17098                 }
17099                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17100                 {
17101                         if (findx > 0)
17102                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17103                         else
17104                                 appendPQExpBufferStr(query, " TRUNCATE");
17105                         findx++;
17106                 }
17107                 appendPQExpBuffer(query, " ON %s\n",
17108                                                   fmtQualifiedDumpable(tbinfo));
17109
17110                 if (tginfo->tgisconstraint)
17111                 {
17112                         if (OidIsValid(tginfo->tgconstrrelid))
17113                         {
17114                                 /* regclass output is already quoted */
17115                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17116                                                                   tginfo->tgconstrrelname);
17117                         }
17118                         if (!tginfo->tgdeferrable)
17119                                 appendPQExpBufferStr(query, "NOT ");
17120                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17121                         if (tginfo->tginitdeferred)
17122                                 appendPQExpBufferStr(query, "DEFERRED\n");
17123                         else
17124                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17125                 }
17126
17127                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17128                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17129                 else
17130                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17131
17132                 /* regproc output is already sufficiently quoted */
17133                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
17134                                                   tginfo->tgfname);
17135
17136                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17137                                                                                   &lentgargs);
17138                 p = tgargs;
17139                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17140                 {
17141                         /* find the embedded null that terminates this trigger argument */
17142                         size_t          tlen = strlen(p);
17143
17144                         if (p + tlen >= tgargs + lentgargs)
17145                         {
17146                                 /* hm, not found before end of bytea value... */
17147                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17148                                                   tginfo->tgargs,
17149                                                   tginfo->dobj.name,
17150                                                   tbinfo->dobj.name);
17151                                 exit_nicely(1);
17152                         }
17153
17154                         if (findx > 0)
17155                                 appendPQExpBufferStr(query, ", ");
17156                         appendStringLiteralAH(query, p, fout);
17157                         p += tlen + 1;
17158                 }
17159                 free(tgargs);
17160                 appendPQExpBufferStr(query, ");\n");
17161         }
17162
17163         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17164         {
17165                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17166                                                   fmtQualifiedDumpable(tbinfo));
17167                 switch (tginfo->tgenabled)
17168                 {
17169                         case 'D':
17170                         case 'f':
17171                                 appendPQExpBufferStr(query, "DISABLE");
17172                                 break;
17173                         case 'A':
17174                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17175                                 break;
17176                         case 'R':
17177                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17178                                 break;
17179                         default:
17180                                 appendPQExpBufferStr(query, "ENABLE");
17181                                 break;
17182                 }
17183                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17184                                                   fmtId(tginfo->dobj.name));
17185         }
17186
17187         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17188                                           fmtId(tginfo->dobj.name));
17189
17190         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17191
17192         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17193                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17194                                          tag,
17195                                          tbinfo->dobj.namespace->dobj.name,
17196                                          NULL,
17197                                          tbinfo->rolname, false,
17198                                          "TRIGGER", SECTION_POST_DATA,
17199                                          query->data, delqry->data, NULL,
17200                                          NULL, 0,
17201                                          NULL, NULL);
17202
17203         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17204                 dumpComment(fout, trigprefix->data, qtabname,
17205                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17206                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17207
17208         free(tag);
17209         destroyPQExpBuffer(query);
17210         destroyPQExpBuffer(delqry);
17211         destroyPQExpBuffer(trigprefix);
17212         free(qtabname);
17213 }
17214
17215 /*
17216  * dumpEventTrigger
17217  *        write the declaration of one user-defined event trigger
17218  */
17219 static void
17220 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17221 {
17222         DumpOptions *dopt = fout->dopt;
17223         PQExpBuffer query;
17224         PQExpBuffer delqry;
17225         char       *qevtname;
17226
17227         /* Skip if not to be dumped */
17228         if (!evtinfo->dobj.dump || dopt->dataOnly)
17229                 return;
17230
17231         query = createPQExpBuffer();
17232         delqry = createPQExpBuffer();
17233
17234         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17235
17236         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17237         appendPQExpBufferStr(query, qevtname);
17238         appendPQExpBufferStr(query, " ON ");
17239         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17240
17241         if (strcmp("", evtinfo->evttags) != 0)
17242         {
17243                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17244                 appendPQExpBufferStr(query, evtinfo->evttags);
17245                 appendPQExpBufferChar(query, ')');
17246         }
17247
17248         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
17249         appendPQExpBufferStr(query, evtinfo->evtfname);
17250         appendPQExpBufferStr(query, "();\n");
17251
17252         if (evtinfo->evtenabled != 'O')
17253         {
17254                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17255                                                   qevtname);
17256                 switch (evtinfo->evtenabled)
17257                 {
17258                         case 'D':
17259                                 appendPQExpBufferStr(query, "DISABLE");
17260                                 break;
17261                         case 'A':
17262                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17263                                 break;
17264                         case 'R':
17265                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17266                                 break;
17267                         default:
17268                                 appendPQExpBufferStr(query, "ENABLE");
17269                                 break;
17270                 }
17271                 appendPQExpBufferStr(query, ";\n");
17272         }
17273
17274         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17275                                           qevtname);
17276
17277         if (dopt->binary_upgrade)
17278                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17279                                                                                 "EVENT TRIGGER", qevtname, NULL);
17280
17281         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17282                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17283                                          evtinfo->dobj.name, NULL, NULL,
17284                                          evtinfo->evtowner, false,
17285                                          "EVENT TRIGGER", SECTION_POST_DATA,
17286                                          query->data, delqry->data, NULL,
17287                                          NULL, 0,
17288                                          NULL, NULL);
17289
17290         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17291                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17292                                         NULL, evtinfo->evtowner,
17293                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17294
17295         destroyPQExpBuffer(query);
17296         destroyPQExpBuffer(delqry);
17297         free(qevtname);
17298 }
17299
17300 /*
17301  * dumpRule
17302  *              Dump a rule
17303  */
17304 static void
17305 dumpRule(Archive *fout, RuleInfo *rinfo)
17306 {
17307         DumpOptions *dopt = fout->dopt;
17308         TableInfo  *tbinfo = rinfo->ruletable;
17309         bool            is_view;
17310         PQExpBuffer query;
17311         PQExpBuffer cmd;
17312         PQExpBuffer delcmd;
17313         PQExpBuffer ruleprefix;
17314         char       *qtabname;
17315         PGresult   *res;
17316         char       *tag;
17317
17318         /* Skip if not to be dumped */
17319         if (!rinfo->dobj.dump || dopt->dataOnly)
17320                 return;
17321
17322         /*
17323          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17324          * we do not want to dump it as a separate object.
17325          */
17326         if (!rinfo->separate)
17327                 return;
17328
17329         /*
17330          * If it's an ON SELECT rule, we want to print it as a view definition,
17331          * instead of a rule.
17332          */
17333         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17334
17335         query = createPQExpBuffer();
17336         cmd = createPQExpBuffer();
17337         delcmd = createPQExpBuffer();
17338         ruleprefix = createPQExpBuffer();
17339
17340         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17341
17342         if (is_view)
17343         {
17344                 PQExpBuffer result;
17345
17346                 /*
17347                  * We need OR REPLACE here because we'll be replacing a dummy view.
17348                  * Otherwise this should look largely like the regular view dump code.
17349                  */
17350                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17351                                                   fmtQualifiedDumpable(tbinfo));
17352                 if (nonemptyReloptions(tbinfo->reloptions))
17353                 {
17354                         appendPQExpBufferStr(cmd, " WITH (");
17355                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17356                         appendPQExpBufferChar(cmd, ')');
17357                 }
17358                 result = createViewAsClause(fout, tbinfo);
17359                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17360                 destroyPQExpBuffer(result);
17361                 if (tbinfo->checkoption != NULL)
17362                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17363                                                           tbinfo->checkoption);
17364                 appendPQExpBufferStr(cmd, ";\n");
17365         }
17366         else
17367         {
17368                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17369                 appendPQExpBuffer(query,
17370                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17371                                                   rinfo->dobj.catId.oid);
17372
17373                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17374
17375                 if (PQntuples(res) != 1)
17376                 {
17377                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17378                                           rinfo->dobj.name, tbinfo->dobj.name);
17379                         exit_nicely(1);
17380                 }
17381
17382                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17383
17384                 PQclear(res);
17385         }
17386
17387         /*
17388          * Add the command to alter the rules replication firing semantics if it
17389          * differs from the default.
17390          */
17391         if (rinfo->ev_enabled != 'O')
17392         {
17393                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17394                 switch (rinfo->ev_enabled)
17395                 {
17396                         case 'A':
17397                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17398                                                                   fmtId(rinfo->dobj.name));
17399                                 break;
17400                         case 'R':
17401                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17402                                                                   fmtId(rinfo->dobj.name));
17403                                 break;
17404                         case 'D':
17405                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17406                                                                   fmtId(rinfo->dobj.name));
17407                                 break;
17408                 }
17409         }
17410
17411         if (is_view)
17412         {
17413                 /*
17414                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17415                  * REPLACE VIEW to replace the rule with something with minimal
17416                  * dependencies.
17417                  */
17418                 PQExpBuffer result;
17419
17420                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17421                                                   fmtQualifiedDumpable(tbinfo));
17422                 result = createDummyViewAsClause(fout, tbinfo);
17423                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17424                 destroyPQExpBuffer(result);
17425         }
17426         else
17427         {
17428                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17429                                                   fmtId(rinfo->dobj.name));
17430                 appendPQExpBuffer(delcmd, "ON %s;\n",
17431                                                   fmtQualifiedDumpable(tbinfo));
17432         }
17433
17434         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17435                                           fmtId(rinfo->dobj.name));
17436
17437         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17438
17439         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17440                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17441                                          tag,
17442                                          tbinfo->dobj.namespace->dobj.name,
17443                                          NULL,
17444                                          tbinfo->rolname, false,
17445                                          "RULE", SECTION_POST_DATA,
17446                                          cmd->data, delcmd->data, NULL,
17447                                          NULL, 0,
17448                                          NULL, NULL);
17449
17450         /* Dump rule comments */
17451         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17452                 dumpComment(fout, ruleprefix->data, qtabname,
17453                                         tbinfo->dobj.namespace->dobj.name,
17454                                         tbinfo->rolname,
17455                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17456
17457         free(tag);
17458         destroyPQExpBuffer(query);
17459         destroyPQExpBuffer(cmd);
17460         destroyPQExpBuffer(delcmd);
17461         destroyPQExpBuffer(ruleprefix);
17462         free(qtabname);
17463 }
17464
17465 /*
17466  * getExtensionMembership --- obtain extension membership data
17467  *
17468  * We need to identify objects that are extension members as soon as they're
17469  * loaded, so that we can correctly determine whether they need to be dumped.
17470  * Generally speaking, extension member objects will get marked as *not* to
17471  * be dumped, as they will be recreated by the single CREATE EXTENSION
17472  * command.  However, in binary upgrade mode we still need to dump the members
17473  * individually.
17474  */
17475 void
17476 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17477                                            int numExtensions)
17478 {
17479         PQExpBuffer query;
17480         PGresult   *res;
17481         int                     ntups,
17482                                 nextmembers,
17483                                 i;
17484         int                     i_classid,
17485                                 i_objid,
17486                                 i_refobjid;
17487         ExtensionMemberId *extmembers;
17488         ExtensionInfo *ext;
17489
17490         /* Nothing to do if no extensions */
17491         if (numExtensions == 0)
17492                 return;
17493
17494         query = createPQExpBuffer();
17495
17496         /* refclassid constraint is redundant but may speed the search */
17497         appendPQExpBufferStr(query, "SELECT "
17498                                                  "classid, objid, refobjid "
17499                                                  "FROM pg_depend "
17500                                                  "WHERE refclassid = 'pg_extension'::regclass "
17501                                                  "AND deptype = 'e' "
17502                                                  "ORDER BY 3");
17503
17504         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17505
17506         ntups = PQntuples(res);
17507
17508         i_classid = PQfnumber(res, "classid");
17509         i_objid = PQfnumber(res, "objid");
17510         i_refobjid = PQfnumber(res, "refobjid");
17511
17512         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17513         nextmembers = 0;
17514
17515         /*
17516          * Accumulate data into extmembers[].
17517          *
17518          * Since we ordered the SELECT by referenced ID, we can expect that
17519          * multiple entries for the same extension will appear together; this
17520          * saves on searches.
17521          */
17522         ext = NULL;
17523
17524         for (i = 0; i < ntups; i++)
17525         {
17526                 CatalogId       objId;
17527                 Oid                     extId;
17528
17529                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17530                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17531                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17532
17533                 if (ext == NULL ||
17534                         ext->dobj.catId.oid != extId)
17535                         ext = findExtensionByOid(extId);
17536
17537                 if (ext == NULL)
17538                 {
17539                         /* shouldn't happen */
17540                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17541                         continue;
17542                 }
17543
17544                 extmembers[nextmembers].catId = objId;
17545                 extmembers[nextmembers].ext = ext;
17546                 nextmembers++;
17547         }
17548
17549         PQclear(res);
17550
17551         /* Remember the data for use later */
17552         setExtensionMembership(extmembers, nextmembers);
17553
17554         destroyPQExpBuffer(query);
17555 }
17556
17557 /*
17558  * processExtensionTables --- deal with extension configuration tables
17559  *
17560  * There are two parts to this process:
17561  *
17562  * 1. Identify and create dump records for extension configuration tables.
17563  *
17564  *        Extensions can mark tables as "configuration", which means that the user
17565  *        is able and expected to modify those tables after the extension has been
17566  *        loaded.  For these tables, we dump out only the data- the structure is
17567  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17568  *        foreign keys, which brings us to-
17569  *
17570  * 2. Record FK dependencies between configuration tables.
17571  *
17572  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17573  *        the data is loaded, we have to work out what the best order for reloading
17574  *        the data is, to avoid FK violations when the tables are restored.  This is
17575  *        not perfect- we can't handle circular dependencies and if any exist they
17576  *        will cause an invalid dump to be produced (though at least all of the data
17577  *        is included for a user to manually restore).  This is currently documented
17578  *        but perhaps we can provide a better solution in the future.
17579  */
17580 void
17581 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17582                                            int numExtensions)
17583 {
17584         DumpOptions *dopt = fout->dopt;
17585         PQExpBuffer query;
17586         PGresult   *res;
17587         int                     ntups,
17588                                 i;
17589         int                     i_conrelid,
17590                                 i_confrelid;
17591
17592         /* Nothing to do if no extensions */
17593         if (numExtensions == 0)
17594                 return;
17595
17596         /*
17597          * Identify extension configuration tables and create TableDataInfo
17598          * objects for them, ensuring their data will be dumped even though the
17599          * tables themselves won't be.
17600          *
17601          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17602          * user data in a configuration table is treated like schema data. This
17603          * seems appropriate since system data in a config table would get
17604          * reloaded by CREATE EXTENSION.
17605          */
17606         for (i = 0; i < numExtensions; i++)
17607         {
17608                 ExtensionInfo *curext = &(extinfo[i]);
17609                 char       *extconfig = curext->extconfig;
17610                 char       *extcondition = curext->extcondition;
17611                 char      **extconfigarray = NULL;
17612                 char      **extconditionarray = NULL;
17613                 int                     nconfigitems;
17614                 int                     nconditionitems;
17615
17616                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17617                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17618                         nconfigitems == nconditionitems)
17619                 {
17620                         int                     j;
17621
17622                         for (j = 0; j < nconfigitems; j++)
17623                         {
17624                                 TableInfo  *configtbl;
17625                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17626                                 bool            dumpobj =
17627                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17628
17629                                 configtbl = findTableByOid(configtbloid);
17630                                 if (configtbl == NULL)
17631                                         continue;
17632
17633                                 /*
17634                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17635                                  * unless the table or its schema is explicitly included
17636                                  */
17637                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17638                                 {
17639                                         /* check table explicitly requested */
17640                                         if (table_include_oids.head != NULL &&
17641                                                 simple_oid_list_member(&table_include_oids,
17642                                                                                            configtbloid))
17643                                                 dumpobj = true;
17644
17645                                         /* check table's schema explicitly requested */
17646                                         if (configtbl->dobj.namespace->dobj.dump &
17647                                                 DUMP_COMPONENT_DATA)
17648                                                 dumpobj = true;
17649                                 }
17650
17651                                 /* check table excluded by an exclusion switch */
17652                                 if (table_exclude_oids.head != NULL &&
17653                                         simple_oid_list_member(&table_exclude_oids,
17654                                                                                    configtbloid))
17655                                         dumpobj = false;
17656
17657                                 /* check schema excluded by an exclusion switch */
17658                                 if (simple_oid_list_member(&schema_exclude_oids,
17659                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17660                                         dumpobj = false;
17661
17662                                 if (dumpobj)
17663                                 {
17664                                         /*
17665                                          * Note: config tables are dumped without OIDs regardless
17666                                          * of the --oids setting.  This is because row filtering
17667                                          * conditions aren't compatible with dumping OIDs.
17668                                          */
17669                                         makeTableDataInfo(dopt, configtbl, false);
17670                                         if (configtbl->dataObj != NULL)
17671                                         {
17672                                                 if (strlen(extconditionarray[j]) > 0)
17673                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17674                                         }
17675                                 }
17676                         }
17677                 }
17678                 if (extconfigarray)
17679                         free(extconfigarray);
17680                 if (extconditionarray)
17681                         free(extconditionarray);
17682         }
17683
17684         /*
17685          * Now that all the TableInfoData objects have been created for all the
17686          * extensions, check their FK dependencies and register them to try and
17687          * dump the data out in an order that they can be restored in.
17688          *
17689          * Note that this is not a problem for user tables as their FKs are
17690          * recreated after the data has been loaded.
17691          */
17692
17693         query = createPQExpBuffer();
17694
17695         printfPQExpBuffer(query,
17696                                           "SELECT conrelid, confrelid "
17697                                           "FROM pg_constraint "
17698                                           "JOIN pg_depend ON (objid = confrelid) "
17699                                           "WHERE contype = 'f' "
17700                                           "AND refclassid = 'pg_extension'::regclass "
17701                                           "AND classid = 'pg_class'::regclass;");
17702
17703         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17704         ntups = PQntuples(res);
17705
17706         i_conrelid = PQfnumber(res, "conrelid");
17707         i_confrelid = PQfnumber(res, "confrelid");
17708
17709         /* Now get the dependencies and register them */
17710         for (i = 0; i < ntups; i++)
17711         {
17712                 Oid                     conrelid,
17713                                         confrelid;
17714                 TableInfo  *reftable,
17715                                    *contable;
17716
17717                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17718                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17719                 contable = findTableByOid(conrelid);
17720                 reftable = findTableByOid(confrelid);
17721
17722                 if (reftable == NULL ||
17723                         reftable->dataObj == NULL ||
17724                         contable == NULL ||
17725                         contable->dataObj == NULL)
17726                         continue;
17727
17728                 /*
17729                  * Make referencing TABLE_DATA object depend on the referenced table's
17730                  * TABLE_DATA object.
17731                  */
17732                 addObjectDependency(&contable->dataObj->dobj,
17733                                                         reftable->dataObj->dobj.dumpId);
17734         }
17735         PQclear(res);
17736         destroyPQExpBuffer(query);
17737 }
17738
17739 /*
17740  * getDependencies --- obtain available dependency data
17741  */
17742 static void
17743 getDependencies(Archive *fout)
17744 {
17745         PQExpBuffer query;
17746         PGresult   *res;
17747         int                     ntups,
17748                                 i;
17749         int                     i_classid,
17750                                 i_objid,
17751                                 i_refclassid,
17752                                 i_refobjid,
17753                                 i_deptype;
17754         DumpableObject *dobj,
17755                            *refdobj;
17756
17757         if (g_verbose)
17758                 write_msg(NULL, "reading dependency data\n");
17759
17760         query = createPQExpBuffer();
17761
17762         /*
17763          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17764          * already processed by getExtensionMembership.
17765          */
17766         appendPQExpBufferStr(query, "SELECT "
17767                                                  "classid, objid, refclassid, refobjid, deptype "
17768                                                  "FROM pg_depend "
17769                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17770                                                  "ORDER BY 1,2");
17771
17772         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17773
17774         ntups = PQntuples(res);
17775
17776         i_classid = PQfnumber(res, "classid");
17777         i_objid = PQfnumber(res, "objid");
17778         i_refclassid = PQfnumber(res, "refclassid");
17779         i_refobjid = PQfnumber(res, "refobjid");
17780         i_deptype = PQfnumber(res, "deptype");
17781
17782         /*
17783          * Since we ordered the SELECT by referencing ID, we can expect that
17784          * multiple entries for the same object will appear together; this saves
17785          * on searches.
17786          */
17787         dobj = NULL;
17788
17789         for (i = 0; i < ntups; i++)
17790         {
17791                 CatalogId       objId;
17792                 CatalogId       refobjId;
17793                 char            deptype;
17794
17795                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17796                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17797                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17798                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17799                 deptype = *(PQgetvalue(res, i, i_deptype));
17800
17801                 if (dobj == NULL ||
17802                         dobj->catId.tableoid != objId.tableoid ||
17803                         dobj->catId.oid != objId.oid)
17804                         dobj = findObjectByCatalogId(objId);
17805
17806                 /*
17807                  * Failure to find objects mentioned in pg_depend is not unexpected,
17808                  * since for example we don't collect info about TOAST tables.
17809                  */
17810                 if (dobj == NULL)
17811                 {
17812 #ifdef NOT_USED
17813                         fprintf(stderr, "no referencing object %u %u\n",
17814                                         objId.tableoid, objId.oid);
17815 #endif
17816                         continue;
17817                 }
17818
17819                 refdobj = findObjectByCatalogId(refobjId);
17820
17821                 if (refdobj == NULL)
17822                 {
17823 #ifdef NOT_USED
17824                         fprintf(stderr, "no referenced object %u %u\n",
17825                                         refobjId.tableoid, refobjId.oid);
17826 #endif
17827                         continue;
17828                 }
17829
17830                 /*
17831                  * Ordinarily, table rowtypes have implicit dependencies on their
17832                  * tables.  However, for a composite type the implicit dependency goes
17833                  * the other way in pg_depend; which is the right thing for DROP but
17834                  * it doesn't produce the dependency ordering we need. So in that one
17835                  * case, we reverse the direction of the dependency.
17836                  */
17837                 if (deptype == 'i' &&
17838                         dobj->objType == DO_TABLE &&
17839                         refdobj->objType == DO_TYPE)
17840                         addObjectDependency(refdobj, dobj->dumpId);
17841                 else
17842                         /* normal case */
17843                         addObjectDependency(dobj, refdobj->dumpId);
17844         }
17845
17846         PQclear(res);
17847
17848         destroyPQExpBuffer(query);
17849 }
17850
17851
17852 /*
17853  * createBoundaryObjects - create dummy DumpableObjects to represent
17854  * dump section boundaries.
17855  */
17856 static DumpableObject *
17857 createBoundaryObjects(void)
17858 {
17859         DumpableObject *dobjs;
17860
17861         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17862
17863         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17864         dobjs[0].catId = nilCatalogId;
17865         AssignDumpId(dobjs + 0);
17866         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17867
17868         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17869         dobjs[1].catId = nilCatalogId;
17870         AssignDumpId(dobjs + 1);
17871         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17872
17873         return dobjs;
17874 }
17875
17876 /*
17877  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17878  * section boundaries.
17879  */
17880 static void
17881 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17882                                                 DumpableObject *boundaryObjs)
17883 {
17884         DumpableObject *preDataBound = boundaryObjs + 0;
17885         DumpableObject *postDataBound = boundaryObjs + 1;
17886         int                     i;
17887
17888         for (i = 0; i < numObjs; i++)
17889         {
17890                 DumpableObject *dobj = dobjs[i];
17891
17892                 /*
17893                  * The classification of object types here must match the SECTION_xxx
17894                  * values assigned during subsequent ArchiveEntry calls!
17895                  */
17896                 switch (dobj->objType)
17897                 {
17898                         case DO_NAMESPACE:
17899                         case DO_EXTENSION:
17900                         case DO_TYPE:
17901                         case DO_SHELL_TYPE:
17902                         case DO_FUNC:
17903                         case DO_AGG:
17904                         case DO_OPERATOR:
17905                         case DO_ACCESS_METHOD:
17906                         case DO_OPCLASS:
17907                         case DO_OPFAMILY:
17908                         case DO_COLLATION:
17909                         case DO_CONVERSION:
17910                         case DO_TABLE:
17911                         case DO_ATTRDEF:
17912                         case DO_PROCLANG:
17913                         case DO_CAST:
17914                         case DO_DUMMY_TYPE:
17915                         case DO_TSPARSER:
17916                         case DO_TSDICT:
17917                         case DO_TSTEMPLATE:
17918                         case DO_TSCONFIG:
17919                         case DO_FDW:
17920                         case DO_FOREIGN_SERVER:
17921                         case DO_TRANSFORM:
17922                         case DO_BLOB:
17923                                 /* Pre-data objects: must come before the pre-data boundary */
17924                                 addObjectDependency(preDataBound, dobj->dumpId);
17925                                 break;
17926                         case DO_TABLE_DATA:
17927                         case DO_SEQUENCE_SET:
17928                         case DO_BLOB_DATA:
17929                                 /* Data objects: must come between the boundaries */
17930                                 addObjectDependency(dobj, preDataBound->dumpId);
17931                                 addObjectDependency(postDataBound, dobj->dumpId);
17932                                 break;
17933                         case DO_INDEX:
17934                         case DO_INDEX_ATTACH:
17935                         case DO_STATSEXT:
17936                         case DO_REFRESH_MATVIEW:
17937                         case DO_TRIGGER:
17938                         case DO_EVENT_TRIGGER:
17939                         case DO_DEFAULT_ACL:
17940                         case DO_POLICY:
17941                         case DO_PUBLICATION:
17942                         case DO_PUBLICATION_REL:
17943                         case DO_SUBSCRIPTION:
17944                                 /* Post-data objects: must come after the post-data boundary */
17945                                 addObjectDependency(dobj, postDataBound->dumpId);
17946                                 break;
17947                         case DO_RULE:
17948                                 /* Rules are post-data, but only if dumped separately */
17949                                 if (((RuleInfo *) dobj)->separate)
17950                                         addObjectDependency(dobj, postDataBound->dumpId);
17951                                 break;
17952                         case DO_CONSTRAINT:
17953                         case DO_FK_CONSTRAINT:
17954                                 /* Constraints are post-data, but only if dumped separately */
17955                                 if (((ConstraintInfo *) dobj)->separate)
17956                                         addObjectDependency(dobj, postDataBound->dumpId);
17957                                 break;
17958                         case DO_PRE_DATA_BOUNDARY:
17959                                 /* nothing to do */
17960                                 break;
17961                         case DO_POST_DATA_BOUNDARY:
17962                                 /* must come after the pre-data boundary */
17963                                 addObjectDependency(dobj, preDataBound->dumpId);
17964                                 break;
17965                 }
17966         }
17967 }
17968
17969
17970 /*
17971  * BuildArchiveDependencies - create dependency data for archive TOC entries
17972  *
17973  * The raw dependency data obtained by getDependencies() is not terribly
17974  * useful in an archive dump, because in many cases there are dependency
17975  * chains linking through objects that don't appear explicitly in the dump.
17976  * For example, a view will depend on its _RETURN rule while the _RETURN rule
17977  * will depend on other objects --- but the rule will not appear as a separate
17978  * object in the dump.  We need to adjust the view's dependencies to include
17979  * whatever the rule depends on that is included in the dump.
17980  *
17981  * Just to make things more complicated, there are also "special" dependencies
17982  * such as the dependency of a TABLE DATA item on its TABLE, which we must
17983  * not rearrange because pg_restore knows that TABLE DATA only depends on
17984  * its table.  In these cases we must leave the dependencies strictly as-is
17985  * even if they refer to not-to-be-dumped objects.
17986  *
17987  * To handle this, the convention is that "special" dependencies are created
17988  * during ArchiveEntry calls, and an archive TOC item that has any such
17989  * entries will not be touched here.  Otherwise, we recursively search the
17990  * DumpableObject data structures to build the correct dependencies for each
17991  * archive TOC item.
17992  */
17993 static void
17994 BuildArchiveDependencies(Archive *fout)
17995 {
17996         ArchiveHandle *AH = (ArchiveHandle *) fout;
17997         TocEntry   *te;
17998
17999         /* Scan all TOC entries in the archive */
18000         for (te = AH->toc->next; te != AH->toc; te = te->next)
18001         {
18002                 DumpableObject *dobj;
18003                 DumpId     *dependencies;
18004                 int                     nDeps;
18005                 int                     allocDeps;
18006
18007                 /* No need to process entries that will not be dumped */
18008                 if (te->reqs == 0)
18009                         continue;
18010                 /* Ignore entries that already have "special" dependencies */
18011                 if (te->nDeps > 0)
18012                         continue;
18013                 /* Otherwise, look up the item's original DumpableObject, if any */
18014                 dobj = findObjectByDumpId(te->dumpId);
18015                 if (dobj == NULL)
18016                         continue;
18017                 /* No work if it has no dependencies */
18018                 if (dobj->nDeps <= 0)
18019                         continue;
18020                 /* Set up work array */
18021                 allocDeps = 64;
18022                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18023                 nDeps = 0;
18024                 /* Recursively find all dumpable dependencies */
18025                 findDumpableDependencies(AH, dobj,
18026                                                                  &dependencies, &nDeps, &allocDeps);
18027                 /* And save 'em ... */
18028                 if (nDeps > 0)
18029                 {
18030                         dependencies = (DumpId *) pg_realloc(dependencies,
18031                                                                                                  nDeps * sizeof(DumpId));
18032                         te->dependencies = dependencies;
18033                         te->nDeps = nDeps;
18034                 }
18035                 else
18036                         free(dependencies);
18037         }
18038 }
18039
18040 /* Recursive search subroutine for BuildArchiveDependencies */
18041 static void
18042 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18043                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18044 {
18045         int                     i;
18046
18047         /*
18048          * Ignore section boundary objects: if we search through them, we'll
18049          * report lots of bogus dependencies.
18050          */
18051         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18052                 dobj->objType == DO_POST_DATA_BOUNDARY)
18053                 return;
18054
18055         for (i = 0; i < dobj->nDeps; i++)
18056         {
18057                 DumpId          depid = dobj->dependencies[i];
18058
18059                 if (TocIDRequired(AH, depid) != 0)
18060                 {
18061                         /* Object will be dumped, so just reference it as a dependency */
18062                         if (*nDeps >= *allocDeps)
18063                         {
18064                                 *allocDeps *= 2;
18065                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18066                                                                                                           *allocDeps * sizeof(DumpId));
18067                         }
18068                         (*dependencies)[*nDeps] = depid;
18069                         (*nDeps)++;
18070                 }
18071                 else
18072                 {
18073                         /*
18074                          * Object will not be dumped, so recursively consider its deps. We
18075                          * rely on the assumption that sortDumpableObjects already broke
18076                          * any dependency loops, else we might recurse infinitely.
18077                          */
18078                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18079
18080                         if (otherdobj)
18081                                 findDumpableDependencies(AH, otherdobj,
18082                                                                                  dependencies, nDeps, allocDeps);
18083                 }
18084         }
18085 }
18086
18087
18088 /*
18089  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18090  * given type OID.
18091  *
18092  * This does not guarantee to schema-qualify the output, so it should not
18093  * be used to create the target object name for CREATE or ALTER commands.
18094  *
18095  * TODO: there might be some value in caching the results.
18096  */
18097 static char *
18098 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18099 {
18100         char       *result;
18101         PQExpBuffer query;
18102         PGresult   *res;
18103
18104         if (oid == 0)
18105         {
18106                 if ((opts & zeroAsOpaque) != 0)
18107                         return pg_strdup(g_opaque_type);
18108                 else if ((opts & zeroAsAny) != 0)
18109                         return pg_strdup("'any'");
18110                 else if ((opts & zeroAsStar) != 0)
18111                         return pg_strdup("*");
18112                 else if ((opts & zeroAsNone) != 0)
18113                         return pg_strdup("NONE");
18114         }
18115
18116         query = createPQExpBuffer();
18117         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18118                                           oid);
18119
18120         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18121
18122         /* result of format_type is already quoted */
18123         result = pg_strdup(PQgetvalue(res, 0, 0));
18124
18125         PQclear(res);
18126         destroyPQExpBuffer(query);
18127
18128         return result;
18129 }
18130
18131 /*
18132  * Return a column list clause for the given relation.
18133  *
18134  * Special case: if there are no undropped columns in the relation, return
18135  * "", not an invalid "()" column list.
18136  */
18137 static const char *
18138 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18139 {
18140         int                     numatts = ti->numatts;
18141         char      **attnames = ti->attnames;
18142         bool       *attisdropped = ti->attisdropped;
18143         bool            needComma;
18144         int                     i;
18145
18146         appendPQExpBufferChar(buffer, '(');
18147         needComma = false;
18148         for (i = 0; i < numatts; i++)
18149         {
18150                 if (attisdropped[i])
18151                         continue;
18152                 if (needComma)
18153                         appendPQExpBufferStr(buffer, ", ");
18154                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18155                 needComma = true;
18156         }
18157
18158         if (!needComma)
18159                 return "";                              /* no undropped columns */
18160
18161         appendPQExpBufferChar(buffer, ')');
18162         return buffer->data;
18163 }
18164
18165 /*
18166  * Check if a reloptions array is nonempty.
18167  */
18168 static bool
18169 nonemptyReloptions(const char *reloptions)
18170 {
18171         /* Don't want to print it if it's just "{}" */
18172         return (reloptions != NULL && strlen(reloptions) > 2);
18173 }
18174
18175 /*
18176  * Format a reloptions array and append it to the given buffer.
18177  *
18178  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18179  */
18180 static void
18181 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18182                                                 const char *prefix, Archive *fout)
18183 {
18184         bool            res;
18185
18186         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18187                                                                 fout->std_strings);
18188         if (!res)
18189                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
18190 }