]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Ensure consistent sort order of large objects in pg_dump.
[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, char relkind);
237 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
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                 {"no-owner", no_argument, NULL, 'O'},
332                 {"port", required_argument, NULL, 'p'},
333                 {"schema", required_argument, NULL, 'n'},
334                 {"exclude-schema", required_argument, NULL, 'N'},
335                 {"schema-only", no_argument, NULL, 's'},
336                 {"superuser", required_argument, NULL, 'S'},
337                 {"table", required_argument, NULL, 't'},
338                 {"exclude-table", required_argument, NULL, 'T'},
339                 {"no-password", no_argument, NULL, 'w'},
340                 {"password", no_argument, NULL, 'W'},
341                 {"username", required_argument, NULL, 'U'},
342                 {"verbose", no_argument, NULL, 'v'},
343                 {"no-privileges", no_argument, NULL, 'x'},
344                 {"no-acl", no_argument, NULL, 'x'},
345                 {"compress", required_argument, NULL, 'Z'},
346                 {"encoding", required_argument, NULL, 'E'},
347                 {"help", no_argument, NULL, '?'},
348                 {"version", no_argument, NULL, 'V'},
349
350                 /*
351                  * the following options don't have an equivalent short option letter
352                  */
353                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
354                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
355                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
356                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
357                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
358                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
359                 {"exclude-table-data", required_argument, NULL, 4},
360                 {"if-exists", no_argument, &dopt.if_exists, 1},
361                 {"inserts", no_argument, &dopt.dump_inserts, 1},
362                 {"lock-wait-timeout", required_argument, NULL, 2},
363                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
364                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
365                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
366                 {"role", required_argument, NULL, 3},
367                 {"section", required_argument, NULL, 5},
368                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
369                 {"snapshot", required_argument, NULL, 6},
370                 {"strict-names", no_argument, &strict_names, 1},
371                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
372                 {"no-comments", no_argument, &dopt.no_comments, 1},
373                 {"no-publications", no_argument, &dopt.no_publications, 1},
374                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
375                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
376                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
377                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
378                 {"no-sync", no_argument, NULL, 7},
379                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
380
381                 {NULL, 0, NULL, 0}
382         };
383
384         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
385
386         /*
387          * Initialize what we need for parallel execution, especially for thread
388          * support on Windows.
389          */
390         init_parallel_dump_utils();
391
392         g_verbose = false;
393
394         strcpy(g_comment_start, "-- ");
395         g_comment_end[0] = '\0';
396         strcpy(g_opaque_type, "opaque");
397
398         progname = get_progname(argv[0]);
399
400         if (argc > 1)
401         {
402                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
403                 {
404                         help(progname);
405                         exit_nicely(0);
406                 }
407                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
408                 {
409                         puts("pg_dump (PostgreSQL) " PG_VERSION);
410                         exit_nicely(0);
411                 }
412         }
413
414         InitDumpOptions(&dopt);
415
416         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
417                                                         long_options, &optindex)) != -1)
418         {
419                 switch (c)
420                 {
421                         case 'a':                       /* Dump data only */
422                                 dopt.dataOnly = true;
423                                 break;
424
425                         case 'b':                       /* Dump blobs */
426                                 dopt.outputBlobs = true;
427                                 break;
428
429                         case 'B':                       /* Don't dump blobs */
430                                 dopt.dontOutputBlobs = true;
431                                 break;
432
433                         case 'c':                       /* clean (i.e., drop) schema prior to create */
434                                 dopt.outputClean = 1;
435                                 break;
436
437                         case 'C':                       /* Create DB */
438                                 dopt.outputCreateDB = 1;
439                                 break;
440
441                         case 'd':                       /* database name */
442                                 dopt.dbname = pg_strdup(optarg);
443                                 break;
444
445                         case 'E':                       /* Dump encoding */
446                                 dumpencoding = pg_strdup(optarg);
447                                 break;
448
449                         case 'f':
450                                 filename = pg_strdup(optarg);
451                                 break;
452
453                         case 'F':
454                                 format = pg_strdup(optarg);
455                                 break;
456
457                         case 'h':                       /* server host */
458                                 dopt.pghost = pg_strdup(optarg);
459                                 break;
460
461                         case 'j':                       /* number of dump jobs */
462                                 numWorkers = atoi(optarg);
463                                 break;
464
465                         case 'n':                       /* include schema(s) */
466                                 simple_string_list_append(&schema_include_patterns, optarg);
467                                 dopt.include_everything = false;
468                                 break;
469
470                         case 'N':                       /* exclude schema(s) */
471                                 simple_string_list_append(&schema_exclude_patterns, optarg);
472                                 break;
473
474                         case 'O':                       /* Don't reconnect to match owner */
475                                 dopt.outputNoOwner = 1;
476                                 break;
477
478                         case 'p':                       /* server port */
479                                 dopt.pgport = pg_strdup(optarg);
480                                 break;
481
482                         case 'R':
483                                 /* no-op, still accepted for backwards compatibility */
484                                 break;
485
486                         case 's':                       /* dump schema only */
487                                 dopt.schemaOnly = true;
488                                 break;
489
490                         case 'S':                       /* Username for superuser in plain text output */
491                                 dopt.outputSuperuser = pg_strdup(optarg);
492                                 break;
493
494                         case 't':                       /* include table(s) */
495                                 simple_string_list_append(&table_include_patterns, optarg);
496                                 dopt.include_everything = false;
497                                 break;
498
499                         case 'T':                       /* exclude table(s) */
500                                 simple_string_list_append(&table_exclude_patterns, optarg);
501                                 break;
502
503                         case 'U':
504                                 dopt.username = pg_strdup(optarg);
505                                 break;
506
507                         case 'v':                       /* verbose */
508                                 g_verbose = true;
509                                 break;
510
511                         case 'w':
512                                 prompt_password = TRI_NO;
513                                 break;
514
515                         case 'W':
516                                 prompt_password = TRI_YES;
517                                 break;
518
519                         case 'x':                       /* skip ACL dump */
520                                 dopt.aclsSkip = true;
521                                 break;
522
523                         case 'Z':                       /* Compression Level */
524                                 compressLevel = atoi(optarg);
525                                 if (compressLevel < 0 || compressLevel > 9)
526                                 {
527                                         write_msg(NULL, "compression level must be in range 0..9\n");
528                                         exit_nicely(1);
529                                 }
530                                 break;
531
532                         case 0:
533                                 /* This covers the long options. */
534                                 break;
535
536                         case 2:                         /* lock-wait-timeout */
537                                 dopt.lockWaitTimeout = pg_strdup(optarg);
538                                 break;
539
540                         case 3:                         /* SET ROLE */
541                                 use_role = pg_strdup(optarg);
542                                 break;
543
544                         case 4:                         /* exclude table(s) data */
545                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
546                                 break;
547
548                         case 5:                         /* section */
549                                 set_dump_section(optarg, &dopt.dumpSections);
550                                 break;
551
552                         case 6:                         /* snapshot */
553                                 dumpsnapshot = pg_strdup(optarg);
554                                 break;
555
556                         case 7:                         /* no-sync */
557                                 dosync = false;
558                                 break;
559
560                         default:
561                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
562                                 exit_nicely(1);
563                 }
564         }
565
566         /*
567          * Non-option argument specifies database name as long as it wasn't
568          * already specified with -d / --dbname
569          */
570         if (optind < argc && dopt.dbname == NULL)
571                 dopt.dbname = argv[optind++];
572
573         /* Complain if any arguments remain */
574         if (optind < argc)
575         {
576                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
577                                 progname, argv[optind]);
578                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
579                                 progname);
580                 exit_nicely(1);
581         }
582
583         /* --column-inserts implies --inserts */
584         if (dopt.column_inserts)
585                 dopt.dump_inserts = 1;
586
587         /*
588          * Binary upgrade mode implies dumping sequence data even in schema-only
589          * mode.  This is not exposed as a separate option, but kept separate
590          * internally for clarity.
591          */
592         if (dopt.binary_upgrade)
593                 dopt.sequence_data = 1;
594
595         if (dopt.dataOnly && dopt.schemaOnly)
596         {
597                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
598                 exit_nicely(1);
599         }
600
601         if (dopt.dataOnly && dopt.outputClean)
602         {
603                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
604                 exit_nicely(1);
605         }
606
607         if (dopt.if_exists && !dopt.outputClean)
608                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
609
610         if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
611                 exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
612
613         /* Identify archive format to emit */
614         archiveFormat = parseArchiveFormat(format, &archiveMode);
615
616         /* archiveFormat specific setup */
617         if (archiveFormat == archNull)
618                 plainText = 1;
619
620         /* Custom and directory formats are compressed by default, others not */
621         if (compressLevel == -1)
622         {
623 #ifdef HAVE_LIBZ
624                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
625                         compressLevel = Z_DEFAULT_COMPRESSION;
626                 else
627 #endif
628                         compressLevel = 0;
629         }
630
631 #ifndef HAVE_LIBZ
632         if (compressLevel != 0)
633                 write_msg(NULL, "WARNING: requested compression not available in this "
634                                   "installation -- archive will be uncompressed\n");
635         compressLevel = 0;
636 #endif
637
638         /*
639          * If emitting an archive format, we always want to emit a DATABASE item,
640          * in case --create is specified at pg_restore time.
641          */
642         if (!plainText)
643                 dopt.outputCreateDB = 1;
644
645         /*
646          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
647          * parallel jobs because that's the maximum limit for the
648          * WaitForMultipleObjects() call.
649          */
650         if (numWorkers <= 0
651 #ifdef WIN32
652                 || numWorkers > MAXIMUM_WAIT_OBJECTS
653 #endif
654                 )
655                 exit_horribly(NULL, "invalid number of parallel jobs\n");
656
657         /* Parallel backup only in the directory archive format so far */
658         if (archiveFormat != archDirectory && numWorkers > 1)
659                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
660
661         /* Open the output file */
662         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
663                                                  archiveMode, setupDumpWorker);
664
665         /* Make dump options accessible right away */
666         SetArchiveOptions(fout, &dopt, NULL);
667
668         /* Register the cleanup hook */
669         on_exit_close_archive(fout);
670
671         /* Let the archiver know how noisy to be */
672         fout->verbose = g_verbose;
673
674         /*
675          * We allow the server to be back to 8.0, and up to any minor release of
676          * our own major version.  (See also version check in pg_dumpall.c.)
677          */
678         fout->minRemoteVersion = 80000;
679         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
680
681         fout->numWorkers = numWorkers;
682
683         /*
684          * Open the database using the Archiver, so it knows about it. Errors mean
685          * death.
686          */
687         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
688         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
689
690         /*
691          * Disable security label support if server version < v9.1.x (prevents
692          * access to nonexistent pg_seclabel catalog)
693          */
694         if (fout->remoteVersion < 90100)
695                 dopt.no_security_labels = 1;
696
697         /*
698          * On hot standbys, never try to dump unlogged table data, since it will
699          * just throw an error.
700          */
701         if (fout->isStandby)
702                 dopt.no_unlogged_table_data = true;
703
704         /* Select the appropriate subquery to convert user IDs to names */
705         if (fout->remoteVersion >= 80100)
706                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
707         else
708                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
709
710         /* check the version for the synchronized snapshots feature */
711         if (numWorkers > 1 && fout->remoteVersion < 90200
712                 && !dopt.no_synchronized_snapshots)
713                 exit_horribly(NULL,
714                                           "Synchronized snapshots are not supported by this server version.\n"
715                                           "Run with --no-synchronized-snapshots instead if you do not need\n"
716                                           "synchronized snapshots.\n");
717
718         /* check the version when a snapshot is explicitly specified by user */
719         if (dumpsnapshot && fout->remoteVersion < 90200)
720                 exit_horribly(NULL,
721                                           "Exported snapshots are not supported by this server version.\n");
722
723         /*
724          * Find the last built-in OID, if needed (prior to 8.1)
725          *
726          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
727          */
728         if (fout->remoteVersion < 80100)
729                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
730         else
731                 g_last_builtin_oid = FirstNormalObjectId - 1;
732
733         if (g_verbose)
734                 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
735
736         /* Expand schema selection patterns into OID lists */
737         if (schema_include_patterns.head != NULL)
738         {
739                 expand_schema_name_patterns(fout, &schema_include_patterns,
740                                                                         &schema_include_oids,
741                                                                         strict_names);
742                 if (schema_include_oids.head == NULL)
743                         exit_horribly(NULL, "no matching schemas were found\n");
744         }
745         expand_schema_name_patterns(fout, &schema_exclude_patterns,
746                                                                 &schema_exclude_oids,
747                                                                 false);
748         /* non-matching exclusion patterns aren't an error */
749
750         /* Expand table selection patterns into OID lists */
751         if (table_include_patterns.head != NULL)
752         {
753                 expand_table_name_patterns(fout, &table_include_patterns,
754                                                                    &table_include_oids,
755                                                                    strict_names);
756                 if (table_include_oids.head == NULL)
757                         exit_horribly(NULL, "no matching tables were found\n");
758         }
759         expand_table_name_patterns(fout, &table_exclude_patterns,
760                                                            &table_exclude_oids,
761                                                            false);
762
763         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
764                                                            &tabledata_exclude_oids,
765                                                            false);
766
767         /* non-matching exclusion patterns aren't an error */
768
769         /*
770          * Dumping blobs is the default for dumps where an inclusion switch is not
771          * used (an "include everything" dump).  -B can be used to exclude blobs
772          * from those dumps.  -b can be used to include blobs even when an
773          * inclusion switch is used.
774          *
775          * -s means "schema only" and blobs are data, not schema, so we never
776          * include blobs when -s is used.
777          */
778         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
779                 dopt.outputBlobs = true;
780
781         /*
782          * Now scan the database and create DumpableObject structs for all the
783          * objects we intend to dump.
784          */
785         tblinfo = getSchemaData(fout, &numTables);
786
787         if (fout->remoteVersion < 80400)
788                 guessConstraintInheritance(tblinfo, numTables);
789
790         if (!dopt.schemaOnly)
791         {
792                 getTableData(&dopt, tblinfo, numTables, 0);
793                 buildMatViewRefreshDependencies(fout);
794                 if (dopt.dataOnly)
795                         getTableDataFKConstraints();
796         }
797
798         if (dopt.schemaOnly && dopt.sequence_data)
799                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
800
801         /*
802          * In binary-upgrade mode, we do not have to worry about the actual blob
803          * data or the associated metadata that resides in the pg_largeobject and
804          * pg_largeobject_metadata tables, respectively.
805          *
806          * However, we do need to collect blob information as there may be
807          * comments or other information on blobs that we do need to dump out.
808          */
809         if (dopt.outputBlobs || dopt.binary_upgrade)
810                 getBlobs(fout);
811
812         /*
813          * Collect dependency data to assist in ordering the objects.
814          */
815         getDependencies(fout);
816
817         /* Lastly, create dummy objects to represent the section boundaries */
818         boundaryObjs = createBoundaryObjects();
819
820         /* Get pointers to all the known DumpableObjects */
821         getDumpableObjects(&dobjs, &numObjs);
822
823         /*
824          * Add dummy dependencies to enforce the dump section ordering.
825          */
826         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
827
828         /*
829          * Sort the objects into a safe dump order (no forward references).
830          *
831          * We rely on dependency information to help us determine a safe order, so
832          * the initial sort is mostly for cosmetic purposes: we sort by name to
833          * ensure that logically identical schemas will dump identically.
834          */
835         sortDumpableObjectsByTypeName(dobjs, numObjs);
836
837         sortDumpableObjects(dobjs, numObjs,
838                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
839
840         /*
841          * Create archive TOC entries for all the objects to be dumped, in a safe
842          * order.
843          */
844
845         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
846         dumpEncoding(fout);
847         dumpStdStrings(fout);
848         dumpSearchPath(fout);
849
850         /* The database items are always next, unless we don't want them at all */
851         if (dopt.outputCreateDB)
852                 dumpDatabase(fout);
853
854         /* Now the rearrangeable objects. */
855         for (i = 0; i < numObjs; i++)
856                 dumpDumpableObject(fout, dobjs[i]);
857
858         /*
859          * Set up options info to ensure we dump what we want.
860          */
861         ropt = NewRestoreOptions();
862         ropt->filename = filename;
863
864         /* if you change this list, see dumpOptionsFromRestoreOptions */
865         ropt->dropSchema = dopt.outputClean;
866         ropt->dataOnly = dopt.dataOnly;
867         ropt->schemaOnly = dopt.schemaOnly;
868         ropt->if_exists = dopt.if_exists;
869         ropt->column_inserts = dopt.column_inserts;
870         ropt->dumpSections = dopt.dumpSections;
871         ropt->aclsSkip = dopt.aclsSkip;
872         ropt->superuser = dopt.outputSuperuser;
873         ropt->createDB = dopt.outputCreateDB;
874         ropt->noOwner = dopt.outputNoOwner;
875         ropt->noTablespace = dopt.outputNoTablespaces;
876         ropt->disable_triggers = dopt.disable_triggers;
877         ropt->use_setsessauth = dopt.use_setsessauth;
878         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
879         ropt->dump_inserts = dopt.dump_inserts;
880         ropt->no_comments = dopt.no_comments;
881         ropt->no_publications = dopt.no_publications;
882         ropt->no_security_labels = dopt.no_security_labels;
883         ropt->no_subscriptions = dopt.no_subscriptions;
884         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
885         ropt->include_everything = dopt.include_everything;
886         ropt->enable_row_security = dopt.enable_row_security;
887         ropt->sequence_data = dopt.sequence_data;
888         ropt->binary_upgrade = dopt.binary_upgrade;
889
890         if (compressLevel == -1)
891                 ropt->compression = 0;
892         else
893                 ropt->compression = compressLevel;
894
895         ropt->suppressDumpWarnings = true;      /* We've already shown them */
896
897         SetArchiveOptions(fout, &dopt, ropt);
898
899         /* Mark which entries should be output */
900         ProcessArchiveRestoreOptions(fout);
901
902         /*
903          * The archive's TOC entries are now marked as to which ones will actually
904          * be output, so we can set up their dependency lists properly. This isn't
905          * necessary for plain-text output, though.
906          */
907         if (!plainText)
908                 BuildArchiveDependencies(fout);
909
910         /*
911          * And finally we can do the actual output.
912          *
913          * Note: for non-plain-text output formats, the output file is written
914          * inside CloseArchive().  This is, um, bizarre; but not worth changing
915          * right now.
916          */
917         if (plainText)
918                 RestoreArchive(fout);
919
920         CloseArchive(fout);
921
922         exit_nicely(0);
923 }
924
925
926 static void
927 help(const char *progname)
928 {
929         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
930         printf(_("Usage:\n"));
931         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
932
933         printf(_("\nGeneral options:\n"));
934         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
935         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
936                          "                               plain text (default))\n"));
937         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
938         printf(_("  -v, --verbose                verbose mode\n"));
939         printf(_("  -V, --version                output version information, then exit\n"));
940         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
941         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
942         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
943         printf(_("  -?, --help                   show this help, then exit\n"));
944
945         printf(_("\nOptions controlling the output content:\n"));
946         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
947         printf(_("  -b, --blobs                  include large objects in dump\n"));
948         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
949         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
950         printf(_("  -C, --create                 include commands to create database in dump\n"));
951         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
952         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
953         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
954         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
955                          "                               plain-text format\n"));
956         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
957         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
958         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
959         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
960         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
961         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
962         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
963         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
964         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
965         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
966                          "                               access to)\n"));
967         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
968         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
969         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
970         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
971         printf(_("  --no-comments                do not dump comments\n"));
972         printf(_("  --no-publications            do not dump publications\n"));
973         printf(_("  --no-security-labels         do not dump security label assignments\n"));
974         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
975         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
976         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
977         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
978         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
979         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
980         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
981         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
982         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
983         printf(_("  --strict-names               require table and/or schema include patterns to\n"
984                          "                               match at least one entity each\n"));
985         printf(_("  --use-set-session-authorization\n"
986                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
987                          "                               ALTER OWNER commands to set ownership\n"));
988
989         printf(_("\nConnection options:\n"));
990         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
991         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
992         printf(_("  -p, --port=PORT          database server port number\n"));
993         printf(_("  -U, --username=NAME      connect as specified database user\n"));
994         printf(_("  -w, --no-password        never prompt for password\n"));
995         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
996         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
997
998         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
999                          "variable value is used.\n\n"));
1000         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1001 }
1002
1003 static void
1004 setup_connection(Archive *AH, const char *dumpencoding,
1005                                  const char *dumpsnapshot, char *use_role)
1006 {
1007         DumpOptions *dopt = AH->dopt;
1008         PGconn     *conn = GetConnection(AH);
1009         const char *std_strings;
1010
1011         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1012
1013         /*
1014          * Set the client encoding if requested.
1015          */
1016         if (dumpencoding)
1017         {
1018                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1019                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1020                                                   dumpencoding);
1021         }
1022
1023         /*
1024          * Get the active encoding and the standard_conforming_strings setting, so
1025          * we know how to escape strings.
1026          */
1027         AH->encoding = PQclientEncoding(conn);
1028
1029         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1030         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1031
1032         /*
1033          * Set the role if requested.  In a parallel dump worker, we'll be passed
1034          * use_role == NULL, but AH->use_role is already set (if user specified it
1035          * originally) and we should use that.
1036          */
1037         if (!use_role && AH->use_role)
1038                 use_role = AH->use_role;
1039
1040         /* Set the role if requested */
1041         if (use_role && AH->remoteVersion >= 80100)
1042         {
1043                 PQExpBuffer query = createPQExpBuffer();
1044
1045                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1046                 ExecuteSqlStatement(AH, query->data);
1047                 destroyPQExpBuffer(query);
1048
1049                 /* save it for possible later use by parallel workers */
1050                 if (!AH->use_role)
1051                         AH->use_role = pg_strdup(use_role);
1052         }
1053
1054         /* Set the datestyle to ISO to ensure the dump's portability */
1055         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1056
1057         /* Likewise, avoid using sql_standard intervalstyle */
1058         if (AH->remoteVersion >= 80400)
1059                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1060
1061         /*
1062          * Set extra_float_digits so that we can dump float data exactly (given
1063          * correctly implemented float I/O code, anyway)
1064          */
1065         if (AH->remoteVersion >= 90000)
1066                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1067         else
1068                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1069
1070         /*
1071          * If synchronized scanning is supported, disable it, to prevent
1072          * unpredictable changes in row ordering across a dump and reload.
1073          */
1074         if (AH->remoteVersion >= 80300)
1075                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1076
1077         /*
1078          * Disable timeouts if supported.
1079          */
1080         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1081         if (AH->remoteVersion >= 90300)
1082                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1083         if (AH->remoteVersion >= 90600)
1084                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1085
1086         /*
1087          * Quote all identifiers, if requested.
1088          */
1089         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1090                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1091
1092         /*
1093          * Adjust row-security mode, if supported.
1094          */
1095         if (AH->remoteVersion >= 90500)
1096         {
1097                 if (dopt->enable_row_security)
1098                         ExecuteSqlStatement(AH, "SET row_security = on");
1099                 else
1100                         ExecuteSqlStatement(AH, "SET row_security = off");
1101         }
1102
1103         /*
1104          * Start transaction-snapshot mode transaction to dump consistent data.
1105          */
1106         ExecuteSqlStatement(AH, "BEGIN");
1107         if (AH->remoteVersion >= 90100)
1108         {
1109                 /*
1110                  * To support the combination of serializable_deferrable with the jobs
1111                  * option we use REPEATABLE READ for the worker connections that are
1112                  * passed a snapshot.  As long as the snapshot is acquired in a
1113                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1114                  * REPEATABLE READ transaction provides the appropriate integrity
1115                  * guarantees.  This is a kluge, but safe for back-patching.
1116                  */
1117                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1118                         ExecuteSqlStatement(AH,
1119                                                                 "SET TRANSACTION ISOLATION LEVEL "
1120                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1121                 else
1122                         ExecuteSqlStatement(AH,
1123                                                                 "SET TRANSACTION ISOLATION LEVEL "
1124                                                                 "REPEATABLE READ, READ ONLY");
1125         }
1126         else
1127         {
1128                 ExecuteSqlStatement(AH,
1129                                                         "SET TRANSACTION ISOLATION LEVEL "
1130                                                         "SERIALIZABLE, READ ONLY");
1131         }
1132
1133         /*
1134          * If user specified a snapshot to use, select that.  In a parallel dump
1135          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1136          * is already set (if the server can handle it) and we should use that.
1137          */
1138         if (dumpsnapshot)
1139                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1140
1141         if (AH->sync_snapshot_id)
1142         {
1143                 PQExpBuffer query = createPQExpBuffer();
1144
1145                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1146                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1147                 ExecuteSqlStatement(AH, query->data);
1148                 destroyPQExpBuffer(query);
1149         }
1150         else if (AH->numWorkers > 1 &&
1151                          AH->remoteVersion >= 90200 &&
1152                          !dopt->no_synchronized_snapshots)
1153         {
1154                 if (AH->isStandby && AH->remoteVersion < 100000)
1155                         exit_horribly(NULL,
1156                                                   "Synchronized snapshots on standby servers are not supported by this server version.\n"
1157                                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1158                                                   "synchronized snapshots.\n");
1159
1160
1161                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1162         }
1163 }
1164
1165 /* Set up connection for a parallel worker process */
1166 static void
1167 setupDumpWorker(Archive *AH)
1168 {
1169         /*
1170          * We want to re-select all the same values the master connection is
1171          * using.  We'll have inherited directly-usable values in
1172          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1173          * inherited encoding value back to a string to pass to setup_connection.
1174          */
1175         setup_connection(AH,
1176                                          pg_encoding_to_char(AH->encoding),
1177                                          NULL,
1178                                          NULL);
1179 }
1180
1181 static char *
1182 get_synchronized_snapshot(Archive *fout)
1183 {
1184         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1185         char       *result;
1186         PGresult   *res;
1187
1188         res = ExecuteSqlQueryForSingleRow(fout, query);
1189         result = pg_strdup(PQgetvalue(res, 0, 0));
1190         PQclear(res);
1191
1192         return result;
1193 }
1194
1195 static ArchiveFormat
1196 parseArchiveFormat(const char *format, ArchiveMode *mode)
1197 {
1198         ArchiveFormat archiveFormat;
1199
1200         *mode = archModeWrite;
1201
1202         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1203         {
1204                 /* This is used by pg_dumpall, and is not documented */
1205                 archiveFormat = archNull;
1206                 *mode = archModeAppend;
1207         }
1208         else if (pg_strcasecmp(format, "c") == 0)
1209                 archiveFormat = archCustom;
1210         else if (pg_strcasecmp(format, "custom") == 0)
1211                 archiveFormat = archCustom;
1212         else if (pg_strcasecmp(format, "d") == 0)
1213                 archiveFormat = archDirectory;
1214         else if (pg_strcasecmp(format, "directory") == 0)
1215                 archiveFormat = archDirectory;
1216         else if (pg_strcasecmp(format, "p") == 0)
1217                 archiveFormat = archNull;
1218         else if (pg_strcasecmp(format, "plain") == 0)
1219                 archiveFormat = archNull;
1220         else if (pg_strcasecmp(format, "t") == 0)
1221                 archiveFormat = archTar;
1222         else if (pg_strcasecmp(format, "tar") == 0)
1223                 archiveFormat = archTar;
1224         else
1225                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1226         return archiveFormat;
1227 }
1228
1229 /*
1230  * Find the OIDs of all schemas matching the given list of patterns,
1231  * and append them to the given OID list.
1232  */
1233 static void
1234 expand_schema_name_patterns(Archive *fout,
1235                                                         SimpleStringList *patterns,
1236                                                         SimpleOidList *oids,
1237                                                         bool strict_names)
1238 {
1239         PQExpBuffer query;
1240         PGresult   *res;
1241         SimpleStringListCell *cell;
1242         int                     i;
1243
1244         if (patterns->head == NULL)
1245                 return;                                 /* nothing to do */
1246
1247         query = createPQExpBuffer();
1248
1249         /*
1250          * The loop below runs multiple SELECTs might sometimes result in
1251          * duplicate entries in the OID list, but we don't care.
1252          */
1253
1254         for (cell = patterns->head; cell; cell = cell->next)
1255         {
1256                 appendPQExpBuffer(query,
1257                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1258                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1259                                                           false, NULL, "n.nspname", NULL, NULL);
1260
1261                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1262                 if (strict_names && PQntuples(res) == 0)
1263                         exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1264
1265                 for (i = 0; i < PQntuples(res); i++)
1266                 {
1267                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1268                 }
1269
1270                 PQclear(res);
1271                 resetPQExpBuffer(query);
1272         }
1273
1274         destroyPQExpBuffer(query);
1275 }
1276
1277 /*
1278  * Find the OIDs of all tables matching the given list of patterns,
1279  * and append them to the given OID list.
1280  */
1281 static void
1282 expand_table_name_patterns(Archive *fout,
1283                                                    SimpleStringList *patterns, SimpleOidList *oids,
1284                                                    bool strict_names)
1285 {
1286         PQExpBuffer query;
1287         PGresult   *res;
1288         SimpleStringListCell *cell;
1289         int                     i;
1290
1291         if (patterns->head == NULL)
1292                 return;                                 /* nothing to do */
1293
1294         query = createPQExpBuffer();
1295
1296         /*
1297          * this might sometimes result in duplicate entries in the OID list, but
1298          * we don't care.
1299          */
1300
1301         for (cell = patterns->head; cell; cell = cell->next)
1302         {
1303                 /*
1304                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1305                  * would be unnecessary given a pg_table_is_visible() variant taking a
1306                  * search_path argument.
1307                  */
1308                 appendPQExpBuffer(query,
1309                                                   "SELECT c.oid"
1310                                                   "\nFROM pg_catalog.pg_class c"
1311                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1312                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1313                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1314                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1315                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1316                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1317                                                   RELKIND_PARTITIONED_TABLE);
1318                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1319                                                           false, "n.nspname", "c.relname", NULL,
1320                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1321
1322                 ExecuteSqlStatement(fout, "RESET search_path");
1323                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1324                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1325                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1326                 if (strict_names && PQntuples(res) == 0)
1327                         exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1328
1329                 for (i = 0; i < PQntuples(res); i++)
1330                 {
1331                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1332                 }
1333
1334                 PQclear(res);
1335                 resetPQExpBuffer(query);
1336         }
1337
1338         destroyPQExpBuffer(query);
1339 }
1340
1341 /*
1342  * checkExtensionMembership
1343  *              Determine whether object is an extension member, and if so,
1344  *              record an appropriate dependency and set the object's dump flag.
1345  *
1346  * It's important to call this for each object that could be an extension
1347  * member.  Generally, we integrate this with determining the object's
1348  * to-be-dumped-ness, since extension membership overrides other rules for that.
1349  *
1350  * Returns true if object is an extension member, else false.
1351  */
1352 static bool
1353 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1354 {
1355         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1356
1357         if (ext == NULL)
1358                 return false;
1359
1360         dobj->ext_member = true;
1361
1362         /* Record dependency so that getDependencies needn't deal with that */
1363         addObjectDependency(dobj, ext->dobj.dumpId);
1364
1365         /*
1366          * In 9.6 and above, mark the member object to have any non-initial ACL,
1367          * policies, and security labels dumped.
1368          *
1369          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1370          * extract the information about the object.  We don't provide support for
1371          * initial policies and security labels and it seems unlikely for those to
1372          * ever exist, but we may have to revisit this later.
1373          *
1374          * Prior to 9.6, we do not include any extension member components.
1375          *
1376          * In binary upgrades, we still dump all components of the members
1377          * individually, since the idea is to exactly reproduce the database
1378          * contents rather than replace the extension contents with something
1379          * different.
1380          */
1381         if (fout->dopt->binary_upgrade)
1382                 dobj->dump = ext->dobj.dump;
1383         else
1384         {
1385                 if (fout->remoteVersion < 90600)
1386                         dobj->dump = DUMP_COMPONENT_NONE;
1387                 else
1388                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1389                                                                                                         DUMP_COMPONENT_SECLABEL |
1390                                                                                                         DUMP_COMPONENT_POLICY);
1391         }
1392
1393         return true;
1394 }
1395
1396 /*
1397  * selectDumpableNamespace: policy-setting subroutine
1398  *              Mark a namespace as to be dumped or not
1399  */
1400 static void
1401 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1402 {
1403         /*
1404          * If specific tables are being dumped, do not dump any complete
1405          * namespaces. If specific namespaces are being dumped, dump just those
1406          * namespaces. Otherwise, dump all non-system namespaces.
1407          */
1408         if (table_include_oids.head != NULL)
1409                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1410         else if (schema_include_oids.head != NULL)
1411                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1412                         simple_oid_list_member(&schema_include_oids,
1413                                                                    nsinfo->dobj.catId.oid) ?
1414                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1415         else if (fout->remoteVersion >= 90600 &&
1416                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1417         {
1418                 /*
1419                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1420                  * they are interesting (and not the original ACLs which were set at
1421                  * initdb time, see pg_init_privs).
1422                  */
1423                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1424         }
1425         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1426                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1427         {
1428                 /* Other system schemas don't get dumped */
1429                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1430         }
1431         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1432         {
1433                 /*
1434                  * The public schema is a strange beast that sits in a sort of
1435                  * no-mans-land between being a system object and a user object.  We
1436                  * don't want to dump creation or comment commands for it, because
1437                  * that complicates matters for non-superuser use of pg_dump.  But we
1438                  * should dump any ACL changes that have occurred for it, and of
1439                  * course we should dump contained objects.
1440                  */
1441                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1442                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1443         }
1444         else
1445                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1446
1447         /*
1448          * In any case, a namespace can be excluded by an exclusion switch
1449          */
1450         if (nsinfo->dobj.dump_contains &&
1451                 simple_oid_list_member(&schema_exclude_oids,
1452                                                            nsinfo->dobj.catId.oid))
1453                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1454
1455         /*
1456          * If the schema belongs to an extension, allow extension membership to
1457          * override the dump decision for the schema itself.  However, this does
1458          * not change dump_contains, so this won't change what we do with objects
1459          * within the schema.  (If they belong to the extension, they'll get
1460          * suppressed by it, otherwise not.)
1461          */
1462         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1463 }
1464
1465 /*
1466  * selectDumpableTable: policy-setting subroutine
1467  *              Mark a table as to be dumped or not
1468  */
1469 static void
1470 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1471 {
1472         if (checkExtensionMembership(&tbinfo->dobj, fout))
1473                 return;                                 /* extension membership overrides all else */
1474
1475         /*
1476          * If specific tables are being dumped, dump just those tables; else, dump
1477          * according to the parent namespace's dump flag.
1478          */
1479         if (table_include_oids.head != NULL)
1480                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1481                                                                                                    tbinfo->dobj.catId.oid) ?
1482                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1483         else
1484                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1485
1486         /*
1487          * In any case, a table can be excluded by an exclusion switch
1488          */
1489         if (tbinfo->dobj.dump &&
1490                 simple_oid_list_member(&table_exclude_oids,
1491                                                            tbinfo->dobj.catId.oid))
1492                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1493 }
1494
1495 /*
1496  * selectDumpableType: policy-setting subroutine
1497  *              Mark a type as to be dumped or not
1498  *
1499  * If it's a table's rowtype or an autogenerated array type, we also apply a
1500  * special type code to facilitate sorting into the desired order.  (We don't
1501  * want to consider those to be ordinary types because that would bring tables
1502  * up into the datatype part of the dump order.)  We still set the object's
1503  * dump flag; that's not going to cause the dummy type to be dumped, but we
1504  * need it so that casts involving such types will be dumped correctly -- see
1505  * dumpCast.  This means the flag should be set the same as for the underlying
1506  * object (the table or base type).
1507  */
1508 static void
1509 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1510 {
1511         /* skip complex types, except for standalone composite types */
1512         if (OidIsValid(tyinfo->typrelid) &&
1513                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1514         {
1515                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1516
1517                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1518                 if (tytable != NULL)
1519                         tyinfo->dobj.dump = tytable->dobj.dump;
1520                 else
1521                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1522                 return;
1523         }
1524
1525         /* skip auto-generated array types */
1526         if (tyinfo->isArray)
1527         {
1528                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1529
1530                 /*
1531                  * Fall through to set the dump flag; we assume that the subsequent
1532                  * rules will do the same thing as they would for the array's base
1533                  * type.  (We cannot reliably look up the base type here, since
1534                  * getTypes may not have processed it yet.)
1535                  */
1536         }
1537
1538         if (checkExtensionMembership(&tyinfo->dobj, fout))
1539                 return;                                 /* extension membership overrides all else */
1540
1541         /* Dump based on if the contents of the namespace are being dumped */
1542         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1543 }
1544
1545 /*
1546  * selectDumpableDefaultACL: policy-setting subroutine
1547  *              Mark a default ACL as to be dumped or not
1548  *
1549  * For per-schema default ACLs, dump if the schema is to be dumped.
1550  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1551  * and aclsSkip are checked separately.
1552  */
1553 static void
1554 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1555 {
1556         /* Default ACLs can't be extension members */
1557
1558         if (dinfo->dobj.namespace)
1559                 /* default ACLs are considered part of the namespace */
1560                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1561         else
1562                 dinfo->dobj.dump = dopt->include_everything ?
1563                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1564 }
1565
1566 /*
1567  * selectDumpableCast: policy-setting subroutine
1568  *              Mark a cast as to be dumped or not
1569  *
1570  * Casts do not belong to any particular namespace (since they haven't got
1571  * names), nor do they have identifiable owners.  To distinguish user-defined
1572  * casts from built-in ones, we must resort to checking whether the cast's
1573  * OID is in the range reserved for initdb.
1574  */
1575 static void
1576 selectDumpableCast(CastInfo *cast, Archive *fout)
1577 {
1578         if (checkExtensionMembership(&cast->dobj, fout))
1579                 return;                                 /* extension membership overrides all else */
1580
1581         /*
1582          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1583          * support ACLs currently.
1584          */
1585         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1586                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1587         else
1588                 cast->dobj.dump = fout->dopt->include_everything ?
1589                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1590 }
1591
1592 /*
1593  * selectDumpableProcLang: policy-setting subroutine
1594  *              Mark a procedural language as to be dumped or not
1595  *
1596  * Procedural languages do not belong to any particular namespace.  To
1597  * identify built-in languages, we must resort to checking whether the
1598  * language's OID is in the range reserved for initdb.
1599  */
1600 static void
1601 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1602 {
1603         if (checkExtensionMembership(&plang->dobj, fout))
1604                 return;                                 /* extension membership overrides all else */
1605
1606         /*
1607          * Only include procedural languages when we are dumping everything.
1608          *
1609          * For from-initdb procedural languages, only include ACLs, as we do for
1610          * the pg_catalog namespace.  We need this because procedural languages do
1611          * not live in any namespace.
1612          */
1613         if (!fout->dopt->include_everything)
1614                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1615         else
1616         {
1617                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1618                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1619                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1620                 else
1621                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1622         }
1623 }
1624
1625 /*
1626  * selectDumpableAccessMethod: policy-setting subroutine
1627  *              Mark an access method as to be dumped or not
1628  *
1629  * Access methods do not belong to any particular namespace.  To identify
1630  * built-in access methods, we must resort to checking whether the
1631  * method's OID is in the range reserved for initdb.
1632  */
1633 static void
1634 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1635 {
1636         if (checkExtensionMembership(&method->dobj, fout))
1637                 return;                                 /* extension membership overrides all else */
1638
1639         /*
1640          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1641          * they do not support ACLs currently.
1642          */
1643         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1644                 method->dobj.dump = DUMP_COMPONENT_NONE;
1645         else
1646                 method->dobj.dump = fout->dopt->include_everything ?
1647                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1648 }
1649
1650 /*
1651  * selectDumpableExtension: policy-setting subroutine
1652  *              Mark an extension as to be dumped or not
1653  *
1654  * Built-in extensions should be skipped except for checking ACLs, since we
1655  * assume those will already be installed in the target database.  We identify
1656  * such extensions by their having OIDs in the range reserved for initdb.
1657  * We dump all user-added extensions by default, or none of them if
1658  * include_everything is false (i.e., a --schema or --table switch was given).
1659  */
1660 static void
1661 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1662 {
1663         /*
1664          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1665          * change permissions on their member objects, if they wish to, and have
1666          * those changes preserved.
1667          */
1668         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1669                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1670         else
1671                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1672                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1673                         DUMP_COMPONENT_NONE;
1674 }
1675
1676 /*
1677  * selectDumpablePublicationTable: policy-setting subroutine
1678  *              Mark a publication table as to be dumped or not
1679  *
1680  * Publication tables have schemas, but those are ignored in decision making,
1681  * because publications are only dumped when we are dumping everything.
1682  */
1683 static void
1684 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1685 {
1686         if (checkExtensionMembership(dobj, fout))
1687                 return;                                 /* extension membership overrides all else */
1688
1689         dobj->dump = fout->dopt->include_everything ?
1690                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1691 }
1692
1693 /*
1694  * selectDumpableObject: policy-setting subroutine
1695  *              Mark a generic dumpable object as to be dumped or not
1696  *
1697  * Use this only for object types without a special-case routine above.
1698  */
1699 static void
1700 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1701 {
1702         if (checkExtensionMembership(dobj, fout))
1703                 return;                                 /* extension membership overrides all else */
1704
1705         /*
1706          * Default policy is to dump if parent namespace is dumpable, or for
1707          * non-namespace-associated items, dump if we're dumping "everything".
1708          */
1709         if (dobj->namespace)
1710                 dobj->dump = dobj->namespace->dobj.dump_contains;
1711         else
1712                 dobj->dump = fout->dopt->include_everything ?
1713                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1714 }
1715
1716 /*
1717  *      Dump a table's contents for loading using the COPY command
1718  *      - this routine is called by the Archiver when it wants the table
1719  *        to be dumped.
1720  */
1721
1722 static int
1723 dumpTableData_copy(Archive *fout, void *dcontext)
1724 {
1725         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1726         TableInfo  *tbinfo = tdinfo->tdtable;
1727         const char *classname = tbinfo->dobj.name;
1728         PQExpBuffer q = createPQExpBuffer();
1729
1730         /*
1731          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1732          * which uses it already.
1733          */
1734         PQExpBuffer clistBuf = createPQExpBuffer();
1735         PGconn     *conn = GetConnection(fout);
1736         PGresult   *res;
1737         int                     ret;
1738         char       *copybuf;
1739         const char *column_list;
1740
1741         if (g_verbose)
1742                 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1743                                   tbinfo->dobj.namespace->dobj.name, classname);
1744
1745         /*
1746          * Specify the column list explicitly so that we have no possibility of
1747          * retrieving data in the wrong column order.  (The default column
1748          * ordering of COPY will not be what we want in certain corner cases
1749          * involving ADD COLUMN and inheritance.)
1750          */
1751         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1752
1753         if (tdinfo->filtercond)
1754         {
1755                 /* Note: this syntax is only supported in 8.2 and up */
1756                 appendPQExpBufferStr(q, "COPY (SELECT ");
1757                 /* klugery to get rid of parens in column list */
1758                 if (strlen(column_list) > 2)
1759                 {
1760                         appendPQExpBufferStr(q, column_list + 1);
1761                         q->data[q->len - 1] = ' ';
1762                 }
1763                 else
1764                         appendPQExpBufferStr(q, "* ");
1765                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1766                                                   fmtQualifiedDumpable(tbinfo),
1767                                                   tdinfo->filtercond);
1768         }
1769         else
1770         {
1771                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1772                                                   fmtQualifiedDumpable(tbinfo),
1773                                                   column_list);
1774         }
1775         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1776         PQclear(res);
1777         destroyPQExpBuffer(clistBuf);
1778
1779         for (;;)
1780         {
1781                 ret = PQgetCopyData(conn, &copybuf, 0);
1782
1783                 if (ret < 0)
1784                         break;                          /* done or error */
1785
1786                 if (copybuf)
1787                 {
1788                         WriteData(fout, copybuf, ret);
1789                         PQfreemem(copybuf);
1790                 }
1791
1792                 /* ----------
1793                  * THROTTLE:
1794                  *
1795                  * There was considerable discussion in late July, 2000 regarding
1796                  * slowing down pg_dump when backing up large tables. Users with both
1797                  * slow & fast (multi-processor) machines experienced performance
1798                  * degradation when doing a backup.
1799                  *
1800                  * Initial attempts based on sleeping for a number of ms for each ms
1801                  * of work were deemed too complex, then a simple 'sleep in each loop'
1802                  * implementation was suggested. The latter failed because the loop
1803                  * was too tight. Finally, the following was implemented:
1804                  *
1805                  * If throttle is non-zero, then
1806                  *              See how long since the last sleep.
1807                  *              Work out how long to sleep (based on ratio).
1808                  *              If sleep is more than 100ms, then
1809                  *                      sleep
1810                  *                      reset timer
1811                  *              EndIf
1812                  * EndIf
1813                  *
1814                  * where the throttle value was the number of ms to sleep per ms of
1815                  * work. The calculation was done in each loop.
1816                  *
1817                  * Most of the hard work is done in the backend, and this solution
1818                  * still did not work particularly well: on slow machines, the ratio
1819                  * was 50:1, and on medium paced machines, 1:1, and on fast
1820                  * multi-processor machines, it had little or no effect, for reasons
1821                  * that were unclear.
1822                  *
1823                  * Further discussion ensued, and the proposal was dropped.
1824                  *
1825                  * For those people who want this feature, it can be implemented using
1826                  * gettimeofday in each loop, calculating the time since last sleep,
1827                  * multiplying that by the sleep ratio, then if the result is more
1828                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1829                  * function to sleep for a subsecond period ie.
1830                  *
1831                  * select(0, NULL, NULL, NULL, &tvi);
1832                  *
1833                  * This will return after the interval specified in the structure tvi.
1834                  * Finally, call gettimeofday again to save the 'last sleep time'.
1835                  * ----------
1836                  */
1837         }
1838         archprintf(fout, "\\.\n\n\n");
1839
1840         if (ret == -2)
1841         {
1842                 /* copy data transfer failed */
1843                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1844                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1845                 write_msg(NULL, "The command was: %s\n", q->data);
1846                 exit_nicely(1);
1847         }
1848
1849         /* Check command status and return to normal libpq state */
1850         res = PQgetResult(conn);
1851         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1852         {
1853                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1854                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1855                 write_msg(NULL, "The command was: %s\n", q->data);
1856                 exit_nicely(1);
1857         }
1858         PQclear(res);
1859
1860         /* Do this to ensure we've pumped libpq back to idle state */
1861         if (PQgetResult(conn) != NULL)
1862                 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1863                                   classname);
1864
1865         destroyPQExpBuffer(q);
1866         return 1;
1867 }
1868
1869 /*
1870  * Dump table data using INSERT commands.
1871  *
1872  * Caution: when we restore from an archive file direct to database, the
1873  * INSERT commands emitted by this function have to be parsed by
1874  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1875  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1876  */
1877 static int
1878 dumpTableData_insert(Archive *fout, void *dcontext)
1879 {
1880         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1881         TableInfo  *tbinfo = tdinfo->tdtable;
1882         DumpOptions *dopt = fout->dopt;
1883         PQExpBuffer q = createPQExpBuffer();
1884         PQExpBuffer insertStmt = NULL;
1885         PGresult   *res;
1886         int                     tuple;
1887         int                     nfields;
1888         int                     field;
1889
1890         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1891                                           "SELECT * FROM ONLY %s",
1892                                           fmtQualifiedDumpable(tbinfo));
1893         if (tdinfo->filtercond)
1894                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1895
1896         ExecuteSqlStatement(fout, q->data);
1897
1898         while (1)
1899         {
1900                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1901                                                           PGRES_TUPLES_OK);
1902                 nfields = PQnfields(res);
1903                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1904                 {
1905                         /*
1906                          * First time through, we build as much of the INSERT statement as
1907                          * possible in "insertStmt", which we can then just print for each
1908                          * line. If the table happens to have zero columns then this will
1909                          * be a complete statement, otherwise it will end in "VALUES(" and
1910                          * be ready to have the row's column values appended.
1911                          */
1912                         if (insertStmt == NULL)
1913                         {
1914                                 TableInfo  *targettab;
1915
1916                                 insertStmt = createPQExpBuffer();
1917
1918                                 /*
1919                                  * When load-via-partition-root is set, get the root table
1920                                  * name for the partition table, so that we can reload data
1921                                  * through the root table.
1922                                  */
1923                                 if (dopt->load_via_partition_root && tbinfo->ispartition)
1924                                         targettab = getRootTableInfo(tbinfo);
1925                                 else
1926                                         targettab = tbinfo;
1927
1928                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1929                                                                   fmtQualifiedDumpable(targettab));
1930
1931                                 /* corner case for zero-column table */
1932                                 if (nfields == 0)
1933                                 {
1934                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1935                                 }
1936                                 else
1937                                 {
1938                                         /* append the list of column names if required */
1939                                         if (dopt->column_inserts)
1940                                         {
1941                                                 appendPQExpBufferChar(insertStmt, '(');
1942                                                 for (field = 0; field < nfields; field++)
1943                                                 {
1944                                                         if (field > 0)
1945                                                                 appendPQExpBufferStr(insertStmt, ", ");
1946                                                         appendPQExpBufferStr(insertStmt,
1947                                                                                                  fmtId(PQfname(res, field)));
1948                                                 }
1949                                                 appendPQExpBufferStr(insertStmt, ") ");
1950                                         }
1951
1952                                         if (tbinfo->needs_override)
1953                                                 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1954
1955                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1956                                 }
1957                         }
1958
1959                         archputs(insertStmt->data, fout);
1960
1961                         /* if it is zero-column table then we're done */
1962                         if (nfields == 0)
1963                                 continue;
1964
1965                         for (field = 0; field < nfields; field++)
1966                         {
1967                                 if (field > 0)
1968                                         archputs(", ", fout);
1969                                 if (PQgetisnull(res, tuple, field))
1970                                 {
1971                                         archputs("NULL", fout);
1972                                         continue;
1973                                 }
1974
1975                                 /* XXX This code is partially duplicated in ruleutils.c */
1976                                 switch (PQftype(res, field))
1977                                 {
1978                                         case INT2OID:
1979                                         case INT4OID:
1980                                         case INT8OID:
1981                                         case OIDOID:
1982                                         case FLOAT4OID:
1983                                         case FLOAT8OID:
1984                                         case NUMERICOID:
1985                                                 {
1986                                                         /*
1987                                                          * These types are printed without quotes unless
1988                                                          * they contain values that aren't accepted by the
1989                                                          * scanner unquoted (e.g., 'NaN').  Note that
1990                                                          * strtod() and friends might accept NaN, so we
1991                                                          * can't use that to test.
1992                                                          *
1993                                                          * In reality we only need to defend against
1994                                                          * infinity and NaN, so we need not get too crazy
1995                                                          * about pattern matching here.
1996                                                          */
1997                                                         const char *s = PQgetvalue(res, tuple, field);
1998
1999                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2000                                                                 archputs(s, fout);
2001                                                         else
2002                                                                 archprintf(fout, "'%s'", s);
2003                                                 }
2004                                                 break;
2005
2006                                         case BITOID:
2007                                         case VARBITOID:
2008                                                 archprintf(fout, "B'%s'",
2009                                                                    PQgetvalue(res, tuple, field));
2010                                                 break;
2011
2012                                         case BOOLOID:
2013                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2014                                                         archputs("true", fout);
2015                                                 else
2016                                                         archputs("false", fout);
2017                                                 break;
2018
2019                                         default:
2020                                                 /* All other types are printed as string literals. */
2021                                                 resetPQExpBuffer(q);
2022                                                 appendStringLiteralAH(q,
2023                                                                                           PQgetvalue(res, tuple, field),
2024                                                                                           fout);
2025                                                 archputs(q->data, fout);
2026                                                 break;
2027                                 }
2028                         }
2029
2030                         if (!dopt->do_nothing)
2031                                 archputs(");\n", fout);
2032                         else
2033                                 archputs(") ON CONFLICT DO NOTHING;\n", fout);
2034                 }
2035
2036                 if (PQntuples(res) <= 0)
2037                 {
2038                         PQclear(res);
2039                         break;
2040                 }
2041                 PQclear(res);
2042         }
2043
2044         archputs("\n\n", fout);
2045
2046         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2047
2048         destroyPQExpBuffer(q);
2049         if (insertStmt != NULL)
2050                 destroyPQExpBuffer(insertStmt);
2051
2052         return 1;
2053 }
2054
2055 /*
2056  * getRootTableInfo:
2057  *     get the root TableInfo for the given partition table.
2058  */
2059 static TableInfo *
2060 getRootTableInfo(TableInfo *tbinfo)
2061 {
2062         TableInfo  *parentTbinfo;
2063
2064         Assert(tbinfo->ispartition);
2065         Assert(tbinfo->numParents == 1);
2066
2067         parentTbinfo = tbinfo->parents[0];
2068         while (parentTbinfo->ispartition)
2069         {
2070                 Assert(parentTbinfo->numParents == 1);
2071                 parentTbinfo = parentTbinfo->parents[0];
2072         }
2073
2074         return parentTbinfo;
2075 }
2076
2077 /*
2078  * dumpTableData -
2079  *        dump the contents of a single table
2080  *
2081  * Actually, this just makes an ArchiveEntry for the table contents.
2082  */
2083 static void
2084 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2085 {
2086         DumpOptions *dopt = fout->dopt;
2087         TableInfo  *tbinfo = tdinfo->tdtable;
2088         PQExpBuffer copyBuf = createPQExpBuffer();
2089         PQExpBuffer clistBuf = createPQExpBuffer();
2090         DataDumperPtr dumpFn;
2091         char       *copyStmt;
2092         const char *copyFrom;
2093
2094         if (!dopt->dump_inserts)
2095         {
2096                 /* Dump/restore using COPY */
2097                 dumpFn = dumpTableData_copy;
2098
2099                 /*
2100                  * When load-via-partition-root is set, get the root table name for
2101                  * the partition table, so that we can reload data through the root
2102                  * table.
2103                  */
2104                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2105                 {
2106                         TableInfo  *parentTbinfo;
2107
2108                         parentTbinfo = getRootTableInfo(tbinfo);
2109                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2110                 }
2111                 else
2112                         copyFrom = fmtQualifiedDumpable(tbinfo);
2113
2114                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2115                 appendPQExpBuffer(copyBuf, "COPY %s ",
2116                                                   copyFrom);
2117                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2118                                                   fmtCopyColumnList(tbinfo, clistBuf));
2119                 copyStmt = copyBuf->data;
2120         }
2121         else
2122         {
2123                 /* Restore using INSERT */
2124                 dumpFn = dumpTableData_insert;
2125                 copyStmt = NULL;
2126         }
2127
2128         /*
2129          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2130          * dependency on its table as "special" and pass it to ArchiveEntry now.
2131          * See comments for BuildArchiveDependencies.
2132          */
2133         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2134         {
2135                 TocEntry   *te;
2136
2137                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2138                                                   tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2139                                                   NULL, tbinfo->rolname,
2140                                                   "TABLE DATA", SECTION_DATA,
2141                                                   "", "", copyStmt,
2142                                                   &(tbinfo->dobj.dumpId), 1,
2143                                                   dumpFn, tdinfo);
2144
2145                 /*
2146                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2147                  * and want to order dump jobs by table size.  We choose to measure
2148                  * dataLength in table pages during dump, so no scaling is needed.
2149                  * However, relpages is declared as "integer" in pg_class, and hence
2150                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2151                  * Cast so that we get the right interpretation of table sizes
2152                  * exceeding INT_MAX pages.
2153                  */
2154                 te->dataLength = (BlockNumber) tbinfo->relpages;
2155         }
2156
2157         destroyPQExpBuffer(copyBuf);
2158         destroyPQExpBuffer(clistBuf);
2159 }
2160
2161 /*
2162  * refreshMatViewData -
2163  *        load or refresh the contents of a single materialized view
2164  *
2165  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2166  * statement.
2167  */
2168 static void
2169 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2170 {
2171         TableInfo  *tbinfo = tdinfo->tdtable;
2172         PQExpBuffer q;
2173
2174         /* If the materialized view is not flagged as populated, skip this. */
2175         if (!tbinfo->relispopulated)
2176                 return;
2177
2178         q = createPQExpBuffer();
2179
2180         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2181                                           fmtQualifiedDumpable(tbinfo));
2182
2183         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2184                 ArchiveEntry(fout,
2185                                          tdinfo->dobj.catId,    /* catalog ID */
2186                                          tdinfo->dobj.dumpId,   /* dump ID */
2187                                          tbinfo->dobj.name, /* Name */
2188                                          tbinfo->dobj.namespace->dobj.name, /* Namespace */
2189                                          NULL,          /* Tablespace */
2190                                          tbinfo->rolname,       /* Owner */
2191                                          "MATERIALIZED VIEW DATA",      /* Desc */
2192                                          SECTION_POST_DATA, /* Section */
2193                                          q->data,       /* Create */
2194                                          "",            /* Del */
2195                                          NULL,          /* Copy */
2196                                          tdinfo->dobj.dependencies, /* Deps */
2197                                          tdinfo->dobj.nDeps,    /* # Deps */
2198                                          NULL,          /* Dumper */
2199                                          NULL);         /* Dumper Arg */
2200
2201         destroyPQExpBuffer(q);
2202 }
2203
2204 /*
2205  * getTableData -
2206  *        set up dumpable objects representing the contents of tables
2207  */
2208 static void
2209 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2210 {
2211         int                     i;
2212
2213         for (i = 0; i < numTables; i++)
2214         {
2215                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2216                         (!relkind || tblinfo[i].relkind == relkind))
2217                         makeTableDataInfo(dopt, &(tblinfo[i]));
2218         }
2219 }
2220
2221 /*
2222  * Make a dumpable object for the data of this specific table
2223  *
2224  * Note: we make a TableDataInfo if and only if we are going to dump the
2225  * table data; the "dump" flag in such objects isn't used.
2226  */
2227 static void
2228 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2229 {
2230         TableDataInfo *tdinfo;
2231
2232         /*
2233          * Nothing to do if we already decided to dump the table.  This will
2234          * happen for "config" tables.
2235          */
2236         if (tbinfo->dataObj != NULL)
2237                 return;
2238
2239         /* Skip VIEWs (no data to dump) */
2240         if (tbinfo->relkind == RELKIND_VIEW)
2241                 return;
2242         /* Skip FOREIGN TABLEs (no data to dump) */
2243         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2244                 return;
2245         /* Skip partitioned tables (data in partitions) */
2246         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2247                 return;
2248
2249         /* Don't dump data in unlogged tables, if so requested */
2250         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2251                 dopt->no_unlogged_table_data)
2252                 return;
2253
2254         /* Check that the data is not explicitly excluded */
2255         if (simple_oid_list_member(&tabledata_exclude_oids,
2256                                                            tbinfo->dobj.catId.oid))
2257                 return;
2258
2259         /* OK, let's dump it */
2260         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2261
2262         if (tbinfo->relkind == RELKIND_MATVIEW)
2263                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2264         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2265                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2266         else
2267                 tdinfo->dobj.objType = DO_TABLE_DATA;
2268
2269         /*
2270          * Note: use tableoid 0 so that this object won't be mistaken for
2271          * something that pg_depend entries apply to.
2272          */
2273         tdinfo->dobj.catId.tableoid = 0;
2274         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2275         AssignDumpId(&tdinfo->dobj);
2276         tdinfo->dobj.name = tbinfo->dobj.name;
2277         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2278         tdinfo->tdtable = tbinfo;
2279         tdinfo->filtercond = NULL;      /* might get set later */
2280         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2281
2282         tbinfo->dataObj = tdinfo;
2283 }
2284
2285 /*
2286  * The refresh for a materialized view must be dependent on the refresh for
2287  * any materialized view that this one is dependent on.
2288  *
2289  * This must be called after all the objects are created, but before they are
2290  * sorted.
2291  */
2292 static void
2293 buildMatViewRefreshDependencies(Archive *fout)
2294 {
2295         PQExpBuffer query;
2296         PGresult   *res;
2297         int                     ntups,
2298                                 i;
2299         int                     i_classid,
2300                                 i_objid,
2301                                 i_refobjid;
2302
2303         /* No Mat Views before 9.3. */
2304         if (fout->remoteVersion < 90300)
2305                 return;
2306
2307         query = createPQExpBuffer();
2308
2309         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2310                                                  "( "
2311                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2312                                                  "FROM pg_depend d1 "
2313                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2314                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2315                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2316                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2317                                                  "AND d2.objid = r1.oid "
2318                                                  "AND d2.refobjid <> d1.objid "
2319                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2320                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2321                                                  CppAsString2(RELKIND_VIEW) ") "
2322                                                  "WHERE d1.classid = 'pg_class'::regclass "
2323                                                  "UNION "
2324                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2325                                                  "FROM w "
2326                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2327                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2328                                                  "AND d3.objid = r3.oid "
2329                                                  "AND d3.refobjid <> w.refobjid "
2330                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2331                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2332                                                  CppAsString2(RELKIND_VIEW) ") "
2333                                                  ") "
2334                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2335                                                  "FROM w "
2336                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2337
2338         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2339
2340         ntups = PQntuples(res);
2341
2342         i_classid = PQfnumber(res, "classid");
2343         i_objid = PQfnumber(res, "objid");
2344         i_refobjid = PQfnumber(res, "refobjid");
2345
2346         for (i = 0; i < ntups; i++)
2347         {
2348                 CatalogId       objId;
2349                 CatalogId       refobjId;
2350                 DumpableObject *dobj;
2351                 DumpableObject *refdobj;
2352                 TableInfo  *tbinfo;
2353                 TableInfo  *reftbinfo;
2354
2355                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2356                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2357                 refobjId.tableoid = objId.tableoid;
2358                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2359
2360                 dobj = findObjectByCatalogId(objId);
2361                 if (dobj == NULL)
2362                         continue;
2363
2364                 Assert(dobj->objType == DO_TABLE);
2365                 tbinfo = (TableInfo *) dobj;
2366                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2367                 dobj = (DumpableObject *) tbinfo->dataObj;
2368                 if (dobj == NULL)
2369                         continue;
2370                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2371
2372                 refdobj = findObjectByCatalogId(refobjId);
2373                 if (refdobj == NULL)
2374                         continue;
2375
2376                 Assert(refdobj->objType == DO_TABLE);
2377                 reftbinfo = (TableInfo *) refdobj;
2378                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2379                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2380                 if (refdobj == NULL)
2381                         continue;
2382                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2383
2384                 addObjectDependency(dobj, refdobj->dumpId);
2385
2386                 if (!reftbinfo->relispopulated)
2387                         tbinfo->relispopulated = false;
2388         }
2389
2390         PQclear(res);
2391
2392         destroyPQExpBuffer(query);
2393 }
2394
2395 /*
2396  * getTableDataFKConstraints -
2397  *        add dump-order dependencies reflecting foreign key constraints
2398  *
2399  * This code is executed only in a data-only dump --- in schema+data dumps
2400  * we handle foreign key issues by not creating the FK constraints until
2401  * after the data is loaded.  In a data-only dump, however, we want to
2402  * order the table data objects in such a way that a table's referenced
2403  * tables are restored first.  (In the presence of circular references or
2404  * self-references this may be impossible; we'll detect and complain about
2405  * that during the dependency sorting step.)
2406  */
2407 static void
2408 getTableDataFKConstraints(void)
2409 {
2410         DumpableObject **dobjs;
2411         int                     numObjs;
2412         int                     i;
2413
2414         /* Search through all the dumpable objects for FK constraints */
2415         getDumpableObjects(&dobjs, &numObjs);
2416         for (i = 0; i < numObjs; i++)
2417         {
2418                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2419                 {
2420                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2421                         TableInfo  *ftable;
2422
2423                         /* Not interesting unless both tables are to be dumped */
2424                         if (cinfo->contable == NULL ||
2425                                 cinfo->contable->dataObj == NULL)
2426                                 continue;
2427                         ftable = findTableByOid(cinfo->confrelid);
2428                         if (ftable == NULL ||
2429                                 ftable->dataObj == NULL)
2430                                 continue;
2431
2432                         /*
2433                          * Okay, make referencing table's TABLE_DATA object depend on the
2434                          * referenced table's TABLE_DATA object.
2435                          */
2436                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2437                                                                 ftable->dataObj->dobj.dumpId);
2438                 }
2439         }
2440         free(dobjs);
2441 }
2442
2443
2444 /*
2445  * guessConstraintInheritance:
2446  *      In pre-8.4 databases, we can't tell for certain which constraints
2447  *      are inherited.  We assume a CHECK constraint is inherited if its name
2448  *      matches the name of any constraint in the parent.  Originally this code
2449  *      tried to compare the expression texts, but that can fail for various
2450  *      reasons --- for example, if the parent and child tables are in different
2451  *      schemas, reverse-listing of function calls may produce different text
2452  *      (schema-qualified or not) depending on search path.
2453  *
2454  *      In 8.4 and up we can rely on the conislocal field to decide which
2455  *      constraints must be dumped; much safer.
2456  *
2457  *      This function assumes all conislocal flags were initialized to true.
2458  *      It clears the flag on anything that seems to be inherited.
2459  */
2460 static void
2461 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2462 {
2463         int                     i,
2464                                 j,
2465                                 k;
2466
2467         for (i = 0; i < numTables; i++)
2468         {
2469                 TableInfo  *tbinfo = &(tblinfo[i]);
2470                 int                     numParents;
2471                 TableInfo **parents;
2472                 TableInfo  *parent;
2473
2474                 /* Sequences and views never have parents */
2475                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2476                         tbinfo->relkind == RELKIND_VIEW)
2477                         continue;
2478
2479                 /* Don't bother computing anything for non-target tables, either */
2480                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2481                         continue;
2482
2483                 numParents = tbinfo->numParents;
2484                 parents = tbinfo->parents;
2485
2486                 if (numParents == 0)
2487                         continue;                       /* nothing to see here, move along */
2488
2489                 /* scan for inherited CHECK constraints */
2490                 for (j = 0; j < tbinfo->ncheck; j++)
2491                 {
2492                         ConstraintInfo *constr;
2493
2494                         constr = &(tbinfo->checkexprs[j]);
2495
2496                         for (k = 0; k < numParents; k++)
2497                         {
2498                                 int                     l;
2499
2500                                 parent = parents[k];
2501                                 for (l = 0; l < parent->ncheck; l++)
2502                                 {
2503                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2504
2505                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2506                                         {
2507                                                 constr->conislocal = false;
2508                                                 break;
2509                                         }
2510                                 }
2511                                 if (!constr->conislocal)
2512                                         break;
2513                         }
2514                 }
2515         }
2516 }
2517
2518
2519 /*
2520  * dumpDatabase:
2521  *      dump the database definition
2522  */
2523 static void
2524 dumpDatabase(Archive *fout)
2525 {
2526         DumpOptions *dopt = fout->dopt;
2527         PQExpBuffer dbQry = createPQExpBuffer();
2528         PQExpBuffer delQry = createPQExpBuffer();
2529         PQExpBuffer creaQry = createPQExpBuffer();
2530         PQExpBuffer labelq = createPQExpBuffer();
2531         PGconn     *conn = GetConnection(fout);
2532         PGresult   *res;
2533         int                     i_tableoid,
2534                                 i_oid,
2535                                 i_datname,
2536                                 i_dba,
2537                                 i_encoding,
2538                                 i_collate,
2539                                 i_ctype,
2540                                 i_frozenxid,
2541                                 i_minmxid,
2542                                 i_datacl,
2543                                 i_rdatacl,
2544                                 i_datistemplate,
2545                                 i_datconnlimit,
2546                                 i_tablespace;
2547         CatalogId       dbCatId;
2548         DumpId          dbDumpId;
2549         const char *datname,
2550                            *dba,
2551                            *encoding,
2552                            *collate,
2553                            *ctype,
2554                            *datacl,
2555                            *rdatacl,
2556                            *datistemplate,
2557                            *datconnlimit,
2558                            *tablespace;
2559         uint32          frozenxid,
2560                                 minmxid;
2561         char       *qdatname;
2562
2563         if (g_verbose)
2564                 write_msg(NULL, "saving database definition\n");
2565
2566         /* Fetch the database-level properties for this database */
2567         if (fout->remoteVersion >= 90600)
2568         {
2569                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2570                                                   "(%s datdba) AS dba, "
2571                                                   "pg_encoding_to_char(encoding) AS encoding, "
2572                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2573                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2574                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2575                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2576                                                   " AS datacl, "
2577                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2578                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2579                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2580                                                   " AS rdatacl, "
2581                                                   "datistemplate, datconnlimit, "
2582                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2583                                                   "shobj_description(oid, 'pg_database') AS description "
2584
2585                                                   "FROM pg_database "
2586                                                   "WHERE datname = current_database()",
2587                                                   username_subquery);
2588         }
2589         else if (fout->remoteVersion >= 90300)
2590         {
2591                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2592                                                   "(%s datdba) AS dba, "
2593                                                   "pg_encoding_to_char(encoding) AS encoding, "
2594                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2595                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2596                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2597                                                   "shobj_description(oid, 'pg_database') AS description "
2598
2599                                                   "FROM pg_database "
2600                                                   "WHERE datname = current_database()",
2601                                                   username_subquery);
2602         }
2603         else if (fout->remoteVersion >= 80400)
2604         {
2605                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2606                                                   "(%s datdba) AS dba, "
2607                                                   "pg_encoding_to_char(encoding) AS encoding, "
2608                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2609                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2610                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2611                                                   "shobj_description(oid, 'pg_database') AS description "
2612
2613                                                   "FROM pg_database "
2614                                                   "WHERE datname = current_database()",
2615                                                   username_subquery);
2616         }
2617         else if (fout->remoteVersion >= 80200)
2618         {
2619                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2620                                                   "(%s datdba) AS dba, "
2621                                                   "pg_encoding_to_char(encoding) AS encoding, "
2622                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2623                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2624                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2625                                                   "shobj_description(oid, 'pg_database') AS description "
2626
2627                                                   "FROM pg_database "
2628                                                   "WHERE datname = current_database()",
2629                                                   username_subquery);
2630         }
2631         else
2632         {
2633                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2634                                                   "(%s datdba) AS dba, "
2635                                                   "pg_encoding_to_char(encoding) AS encoding, "
2636                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2637                                                   "datacl, '' as rdatacl, datistemplate, "
2638                                                   "-1 as datconnlimit, "
2639                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2640                                                   "FROM pg_database "
2641                                                   "WHERE datname = current_database()",
2642                                                   username_subquery);
2643         }
2644
2645         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2646
2647         i_tableoid = PQfnumber(res, "tableoid");
2648         i_oid = PQfnumber(res, "oid");
2649         i_datname = PQfnumber(res, "datname");
2650         i_dba = PQfnumber(res, "dba");
2651         i_encoding = PQfnumber(res, "encoding");
2652         i_collate = PQfnumber(res, "datcollate");
2653         i_ctype = PQfnumber(res, "datctype");
2654         i_frozenxid = PQfnumber(res, "datfrozenxid");
2655         i_minmxid = PQfnumber(res, "datminmxid");
2656         i_datacl = PQfnumber(res, "datacl");
2657         i_rdatacl = PQfnumber(res, "rdatacl");
2658         i_datistemplate = PQfnumber(res, "datistemplate");
2659         i_datconnlimit = PQfnumber(res, "datconnlimit");
2660         i_tablespace = PQfnumber(res, "tablespace");
2661
2662         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2663         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2664         datname = PQgetvalue(res, 0, i_datname);
2665         dba = PQgetvalue(res, 0, i_dba);
2666         encoding = PQgetvalue(res, 0, i_encoding);
2667         collate = PQgetvalue(res, 0, i_collate);
2668         ctype = PQgetvalue(res, 0, i_ctype);
2669         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2670         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2671         datacl = PQgetvalue(res, 0, i_datacl);
2672         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2673         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2674         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2675         tablespace = PQgetvalue(res, 0, i_tablespace);
2676
2677         qdatname = pg_strdup(fmtId(datname));
2678
2679         /*
2680          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2681          * and tablespace since those can't be altered later.  Other DB properties
2682          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2683          * after reconnecting to the target DB.
2684          */
2685         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2686                                           qdatname);
2687         if (strlen(encoding) > 0)
2688         {
2689                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2690                 appendStringLiteralAH(creaQry, encoding, fout);
2691         }
2692         if (strlen(collate) > 0)
2693         {
2694                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2695                 appendStringLiteralAH(creaQry, collate, fout);
2696         }
2697         if (strlen(ctype) > 0)
2698         {
2699                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2700                 appendStringLiteralAH(creaQry, ctype, fout);
2701         }
2702
2703         /*
2704          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2705          * thing; the decision whether to specify a tablespace should be left till
2706          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2707          * label the DATABASE entry with the tablespace and let the normal
2708          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2709          * attention to default_tablespace, so that won't work.
2710          */
2711         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2712                 !dopt->outputNoTablespaces)
2713                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2714                                                   fmtId(tablespace));
2715         appendPQExpBufferStr(creaQry, ";\n");
2716
2717         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2718                                           qdatname);
2719
2720         dbDumpId = createDumpId();
2721
2722         ArchiveEntry(fout,
2723                                  dbCatId,               /* catalog ID */
2724                                  dbDumpId,              /* dump ID */
2725                                  datname,               /* Name */
2726                                  NULL,                  /* Namespace */
2727                                  NULL,                  /* Tablespace */
2728                                  dba,                   /* Owner */
2729                                  "DATABASE",    /* Desc */
2730                                  SECTION_PRE_DATA,      /* Section */
2731                                  creaQry->data, /* Create */
2732                                  delQry->data,  /* Del */
2733                                  NULL,                  /* Copy */
2734                                  NULL,                  /* Deps */
2735                                  0,                             /* # Deps */
2736                                  NULL,                  /* Dumper */
2737                                  NULL);                 /* Dumper Arg */
2738
2739         /* Compute correct tag for archive entry */
2740         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2741
2742         /* Dump DB comment if any */
2743         if (fout->remoteVersion >= 80200)
2744         {
2745                 /*
2746                  * 8.2 and up keep comments on shared objects in a shared table, so we
2747                  * cannot use the dumpComment() code used for other database objects.
2748                  * Be careful that the ArchiveEntry parameters match that function.
2749                  */
2750                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2751
2752                 if (comment && *comment && !dopt->no_comments)
2753                 {
2754                         resetPQExpBuffer(dbQry);
2755
2756                         /*
2757                          * Generates warning when loaded into a differently-named
2758                          * database.
2759                          */
2760                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2761                         appendStringLiteralAH(dbQry, comment, fout);
2762                         appendPQExpBufferStr(dbQry, ";\n");
2763
2764                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2765                                                  labelq->data, NULL, NULL, dba,
2766                                                  "COMMENT", SECTION_NONE,
2767                                                  dbQry->data, "", NULL,
2768                                                  &(dbDumpId), 1,
2769                                                  NULL, NULL);
2770                 }
2771         }
2772         else
2773         {
2774                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2775                                         dbCatId, 0, dbDumpId);
2776         }
2777
2778         /* Dump DB security label, if enabled */
2779         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2780         {
2781                 PGresult   *shres;
2782                 PQExpBuffer seclabelQry;
2783
2784                 seclabelQry = createPQExpBuffer();
2785
2786                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2787                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2788                 resetPQExpBuffer(seclabelQry);
2789                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2790                 if (seclabelQry->len > 0)
2791                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2792                                                  labelq->data, NULL, NULL, dba,
2793                                                  "SECURITY LABEL", SECTION_NONE,
2794                                                  seclabelQry->data, "", NULL,
2795                                                  &(dbDumpId), 1,
2796                                                  NULL, NULL);
2797                 destroyPQExpBuffer(seclabelQry);
2798                 PQclear(shres);
2799         }
2800
2801         /*
2802          * Dump ACL if any.  Note that we do not support initial privileges
2803          * (pg_init_privs) on databases.
2804          */
2805         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2806                         qdatname, NULL, NULL,
2807                         dba, datacl, rdatacl, "", "");
2808
2809         /*
2810          * Now construct a DATABASE PROPERTIES archive entry to restore any
2811          * non-default database-level properties.  (The reason this must be
2812          * separate is that we cannot put any additional commands into the TOC
2813          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2814          * in an implicit transaction block, and the backend won't allow CREATE
2815          * DATABASE in that context.)
2816          */
2817         resetPQExpBuffer(creaQry);
2818         resetPQExpBuffer(delQry);
2819
2820         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2821                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2822                                                   qdatname, datconnlimit);
2823
2824         if (strcmp(datistemplate, "t") == 0)
2825         {
2826                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2827                                                   qdatname);
2828
2829                 /*
2830                  * The backend won't accept DROP DATABASE on a template database.  We
2831                  * can deal with that by removing the template marking before the DROP
2832                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2833                  * since no such command is currently supported, fake it with a direct
2834                  * UPDATE on pg_database.
2835                  */
2836                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2837                                                          "SET datistemplate = false WHERE datname = ");
2838                 appendStringLiteralAH(delQry, datname, fout);
2839                 appendPQExpBufferStr(delQry, ";\n");
2840         }
2841
2842         /* Add database-specific SET options */
2843         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2844
2845         /*
2846          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2847          * entry, too, for lack of a better place.
2848          */
2849         if (dopt->binary_upgrade)
2850         {
2851                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2852                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2853                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2854                                                   "WHERE datname = ",
2855                                                   frozenxid, minmxid);
2856                 appendStringLiteralAH(creaQry, datname, fout);
2857                 appendPQExpBufferStr(creaQry, ";\n");
2858         }
2859
2860         if (creaQry->len > 0)
2861                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2862                                          datname, NULL, NULL, dba,
2863                                          "DATABASE PROPERTIES", SECTION_PRE_DATA,
2864                                          creaQry->data, delQry->data, NULL,
2865                                          &(dbDumpId), 1,
2866                                          NULL, NULL);
2867
2868         /*
2869          * pg_largeobject comes from the old system intact, so set its
2870          * relfrozenxids and relminmxids.
2871          */
2872         if (dopt->binary_upgrade)
2873         {
2874                 PGresult   *lo_res;
2875                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2876                 PQExpBuffer loOutQry = createPQExpBuffer();
2877                 int                     i_relfrozenxid,
2878                                         i_relminmxid;
2879
2880                 /*
2881                  * pg_largeobject
2882                  */
2883                 if (fout->remoteVersion >= 90300)
2884                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2885                                                           "FROM pg_catalog.pg_class\n"
2886                                                           "WHERE oid = %u;\n",
2887                                                           LargeObjectRelationId);
2888                 else
2889                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2890                                                           "FROM pg_catalog.pg_class\n"
2891                                                           "WHERE oid = %u;\n",
2892                                                           LargeObjectRelationId);
2893
2894                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2895
2896                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2897                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2898
2899                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2900                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2901                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2902                                                   "WHERE oid = %u;\n",
2903                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2904                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2905                                                   LargeObjectRelationId);
2906                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2907                                          "pg_largeobject", NULL, NULL, "",
2908                                          "pg_largeobject", SECTION_PRE_DATA,
2909                                          loOutQry->data, "", NULL,
2910                                          NULL, 0,
2911                                          NULL, NULL);
2912
2913                 PQclear(lo_res);
2914
2915                 destroyPQExpBuffer(loFrozenQry);
2916                 destroyPQExpBuffer(loOutQry);
2917         }
2918
2919         PQclear(res);
2920
2921         free(qdatname);
2922         destroyPQExpBuffer(dbQry);
2923         destroyPQExpBuffer(delQry);
2924         destroyPQExpBuffer(creaQry);
2925         destroyPQExpBuffer(labelq);
2926 }
2927
2928 /*
2929  * Collect any database-specific or role-and-database-specific SET options
2930  * for this database, and append them to outbuf.
2931  */
2932 static void
2933 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
2934                                    const char *dbname, Oid dboid)
2935 {
2936         PGconn     *conn = GetConnection(AH);
2937         PQExpBuffer buf = createPQExpBuffer();
2938         PGresult   *res;
2939         int                     count = 1;
2940
2941         /*
2942          * First collect database-specific options.  Pre-8.4 server versions lack
2943          * unnest(), so we do this the hard way by querying once per subscript.
2944          */
2945         for (;;)
2946         {
2947                 if (AH->remoteVersion >= 90000)
2948                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
2949                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
2950                                                           count, dboid);
2951                 else
2952                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
2953
2954                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
2955
2956                 if (PQntuples(res) == 1 &&
2957                         !PQgetisnull(res, 0, 0))
2958                 {
2959                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
2960                                                                    "DATABASE", dbname, NULL, NULL,
2961                                                                    outbuf);
2962                         PQclear(res);
2963                         count++;
2964                 }
2965                 else
2966                 {
2967                         PQclear(res);
2968                         break;
2969                 }
2970         }
2971
2972         /* Now look for role-and-database-specific options */
2973         if (AH->remoteVersion >= 90000)
2974         {
2975                 /* Here we can assume we have unnest() */
2976                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
2977                                                   "FROM pg_db_role_setting s, pg_roles r "
2978                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
2979                                                   dboid);
2980
2981                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
2982
2983                 if (PQntuples(res) > 0)
2984                 {
2985                         int                     i;
2986
2987                         for (i = 0; i < PQntuples(res); i++)
2988                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
2989                                                                            "ROLE", PQgetvalue(res, i, 0),
2990                                                                            "DATABASE", dbname,
2991                                                                            outbuf);
2992                 }
2993
2994                 PQclear(res);
2995         }
2996
2997         destroyPQExpBuffer(buf);
2998 }
2999
3000 /*
3001  * dumpEncoding: put the correct encoding into the archive
3002  */
3003 static void
3004 dumpEncoding(Archive *AH)
3005 {
3006         const char *encname = pg_encoding_to_char(AH->encoding);
3007         PQExpBuffer qry = createPQExpBuffer();
3008
3009         if (g_verbose)
3010                 write_msg(NULL, "saving encoding = %s\n", encname);
3011
3012         appendPQExpBufferStr(qry, "SET client_encoding = ");
3013         appendStringLiteralAH(qry, encname, AH);
3014         appendPQExpBufferStr(qry, ";\n");
3015
3016         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3017                                  "ENCODING", NULL, NULL, "",
3018                                  "ENCODING", SECTION_PRE_DATA,
3019                                  qry->data, "", NULL,
3020                                  NULL, 0,
3021                                  NULL, NULL);
3022
3023         destroyPQExpBuffer(qry);
3024 }
3025
3026
3027 /*
3028  * dumpStdStrings: put the correct escape string behavior into the archive
3029  */
3030 static void
3031 dumpStdStrings(Archive *AH)
3032 {
3033         const char *stdstrings = AH->std_strings ? "on" : "off";
3034         PQExpBuffer qry = createPQExpBuffer();
3035
3036         if (g_verbose)
3037                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3038                                   stdstrings);
3039
3040         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3041                                           stdstrings);
3042
3043         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3044                                  "STDSTRINGS", NULL, NULL, "",
3045                                  "STDSTRINGS", SECTION_PRE_DATA,
3046                                  qry->data, "", NULL,
3047                                  NULL, 0,
3048                                  NULL, NULL);
3049
3050         destroyPQExpBuffer(qry);
3051 }
3052
3053 /*
3054  * dumpSearchPath: record the active search_path in the archive
3055  */
3056 static void
3057 dumpSearchPath(Archive *AH)
3058 {
3059         PQExpBuffer qry = createPQExpBuffer();
3060         PQExpBuffer path = createPQExpBuffer();
3061         PGresult   *res;
3062         char      **schemanames = NULL;
3063         int                     nschemanames = 0;
3064         int                     i;
3065
3066         /*
3067          * We use the result of current_schemas(), not the search_path GUC,
3068          * because that might contain wildcards such as "$user", which won't
3069          * necessarily have the same value during restore.  Also, this way avoids
3070          * listing schemas that may appear in search_path but not actually exist,
3071          * which seems like a prudent exclusion.
3072          */
3073         res = ExecuteSqlQueryForSingleRow(AH,
3074                                                                           "SELECT pg_catalog.current_schemas(false)");
3075
3076         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3077                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3078
3079         /*
3080          * We use set_config(), not a simple "SET search_path" command, because
3081          * the latter has less-clean behavior if the search path is empty.  While
3082          * that's likely to get fixed at some point, it seems like a good idea to
3083          * be as backwards-compatible as possible in what we put into archives.
3084          */
3085         for (i = 0; i < nschemanames; i++)
3086         {
3087                 if (i > 0)
3088                         appendPQExpBufferStr(path, ", ");
3089                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3090         }
3091
3092         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3093         appendStringLiteralAH(qry, path->data, AH);
3094         appendPQExpBufferStr(qry, ", false);\n");
3095
3096         if (g_verbose)
3097                 write_msg(NULL, "saving search_path = %s\n", path->data);
3098
3099         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3100                                  "SEARCHPATH", NULL, NULL, "",
3101                                  "SEARCHPATH", SECTION_PRE_DATA,
3102                                  qry->data, "", NULL,
3103                                  NULL, 0,
3104                                  NULL, NULL);
3105
3106         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3107         AH->searchpath = pg_strdup(qry->data);
3108
3109         if (schemanames)
3110                 free(schemanames);
3111         PQclear(res);
3112         destroyPQExpBuffer(qry);
3113         destroyPQExpBuffer(path);
3114 }
3115
3116
3117 /*
3118  * getBlobs:
3119  *      Collect schema-level data about large objects
3120  */
3121 static void
3122 getBlobs(Archive *fout)
3123 {
3124         DumpOptions *dopt = fout->dopt;
3125         PQExpBuffer blobQry = createPQExpBuffer();
3126         BlobInfo   *binfo;
3127         DumpableObject *bdata;
3128         PGresult   *res;
3129         int                     ntups;
3130         int                     i;
3131         int                     i_oid;
3132         int                     i_lomowner;
3133         int                     i_lomacl;
3134         int                     i_rlomacl;
3135         int                     i_initlomacl;
3136         int                     i_initrlomacl;
3137
3138         /* Verbose message */
3139         if (g_verbose)
3140                 write_msg(NULL, "reading large objects\n");
3141
3142         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3143         if (fout->remoteVersion >= 90600)
3144         {
3145                 PQExpBuffer acl_subquery = createPQExpBuffer();
3146                 PQExpBuffer racl_subquery = createPQExpBuffer();
3147                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3148                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3149
3150                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3151                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3152                                                 dopt->binary_upgrade);
3153
3154                 appendPQExpBuffer(blobQry,
3155                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3156                                                   "%s AS lomacl, "
3157                                                   "%s AS rlomacl, "
3158                                                   "%s AS initlomacl, "
3159                                                   "%s AS initrlomacl "
3160                                                   "FROM pg_largeobject_metadata l "
3161                                                   "LEFT JOIN pg_init_privs pip ON "
3162                                                   "(l.oid = pip.objoid "
3163                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3164                                                   "AND pip.objsubid = 0) ",
3165                                                   username_subquery,
3166                                                   acl_subquery->data,
3167                                                   racl_subquery->data,
3168                                                   init_acl_subquery->data,
3169                                                   init_racl_subquery->data);
3170
3171                 destroyPQExpBuffer(acl_subquery);
3172                 destroyPQExpBuffer(racl_subquery);
3173                 destroyPQExpBuffer(init_acl_subquery);
3174                 destroyPQExpBuffer(init_racl_subquery);
3175         }
3176         else if (fout->remoteVersion >= 90000)
3177                 appendPQExpBuffer(blobQry,
3178                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3179                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3180                                                   "NULL AS initrlomacl "
3181                                                   " FROM pg_largeobject_metadata",
3182                                                   username_subquery);
3183         else
3184                 appendPQExpBufferStr(blobQry,
3185                                                          "SELECT DISTINCT loid AS oid, "
3186                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3187                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3188                                                          "NULL::oid AS initrlomacl "
3189                                                          " FROM pg_largeobject");
3190
3191         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3192
3193         i_oid = PQfnumber(res, "oid");
3194         i_lomowner = PQfnumber(res, "rolname");
3195         i_lomacl = PQfnumber(res, "lomacl");
3196         i_rlomacl = PQfnumber(res, "rlomacl");
3197         i_initlomacl = PQfnumber(res, "initlomacl");
3198         i_initrlomacl = PQfnumber(res, "initrlomacl");
3199
3200         ntups = PQntuples(res);
3201
3202         /*
3203          * Each large object has its own BLOB archive entry.
3204          */
3205         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3206
3207         for (i = 0; i < ntups; i++)
3208         {
3209                 binfo[i].dobj.objType = DO_BLOB;
3210                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3211                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3212                 AssignDumpId(&binfo[i].dobj);
3213
3214                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3215                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3216                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3217                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3218                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3219                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3220
3221                 if (PQgetisnull(res, i, i_lomacl) &&
3222                         PQgetisnull(res, i, i_rlomacl) &&
3223                         PQgetisnull(res, i, i_initlomacl) &&
3224                         PQgetisnull(res, i, i_initrlomacl))
3225                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3226
3227                 /*
3228                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3229                  * data, as it will be copied by pg_upgrade, which simply copies the
3230                  * pg_largeobject table. We *do* however dump out anything but the
3231                  * data, as pg_upgrade copies just pg_largeobject, but not
3232                  * pg_largeobject_metadata, after the dump is restored.
3233                  */
3234                 if (dopt->binary_upgrade)
3235                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3236         }
3237
3238         /*
3239          * If we have any large objects, a "BLOBS" archive entry is needed. This
3240          * is just a placeholder for sorting; it carries no data now.
3241          */
3242         if (ntups > 0)
3243         {
3244                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3245                 bdata->objType = DO_BLOB_DATA;
3246                 bdata->catId = nilCatalogId;
3247                 AssignDumpId(bdata);
3248                 bdata->name = pg_strdup("BLOBS");
3249         }
3250
3251         PQclear(res);
3252         destroyPQExpBuffer(blobQry);
3253 }
3254
3255 /*
3256  * dumpBlob
3257  *
3258  * dump the definition (metadata) of the given large object
3259  */
3260 static void
3261 dumpBlob(Archive *fout, BlobInfo *binfo)
3262 {
3263         PQExpBuffer cquery = createPQExpBuffer();
3264         PQExpBuffer dquery = createPQExpBuffer();
3265
3266         appendPQExpBuffer(cquery,
3267                                           "SELECT pg_catalog.lo_create('%s');\n",
3268                                           binfo->dobj.name);
3269
3270         appendPQExpBuffer(dquery,
3271                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3272                                           binfo->dobj.name);
3273
3274         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3275                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3276                                          binfo->dobj.name,
3277                                          NULL, NULL,
3278                                          binfo->rolname,
3279                                          "BLOB", SECTION_PRE_DATA,
3280                                          cquery->data, dquery->data, NULL,
3281                                          NULL, 0,
3282                                          NULL, NULL);
3283
3284         /* Dump comment if any */
3285         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3286                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3287                                         NULL, binfo->rolname,
3288                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3289
3290         /* Dump security label if any */
3291         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3292                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3293                                          NULL, binfo->rolname,
3294                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3295
3296         /* Dump ACL if any */
3297         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3298                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3299                                 binfo->dobj.name, NULL,
3300                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3301                                 binfo->initblobacl, binfo->initrblobacl);
3302
3303         destroyPQExpBuffer(cquery);
3304         destroyPQExpBuffer(dquery);
3305 }
3306
3307 /*
3308  * dumpBlobs:
3309  *      dump the data contents of all large objects
3310  */
3311 static int
3312 dumpBlobs(Archive *fout, void *arg)
3313 {
3314         const char *blobQry;
3315         const char *blobFetchQry;
3316         PGconn     *conn = GetConnection(fout);
3317         PGresult   *res;
3318         char            buf[LOBBUFSIZE];
3319         int                     ntups;
3320         int                     i;
3321         int                     cnt;
3322
3323         if (g_verbose)
3324                 write_msg(NULL, "saving large objects\n");
3325
3326         /*
3327          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3328          * the already-in-memory dumpable objects instead...
3329          */
3330         if (fout->remoteVersion >= 90000)
3331                 blobQry =
3332                         "DECLARE bloboid CURSOR FOR "
3333                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3334         else
3335                 blobQry =
3336                         "DECLARE bloboid CURSOR FOR "
3337                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3338
3339         ExecuteSqlStatement(fout, blobQry);
3340
3341         /* Command to fetch from cursor */
3342         blobFetchQry = "FETCH 1000 IN bloboid";
3343
3344         do
3345         {
3346                 /* Do a fetch */
3347                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3348
3349                 /* Process the tuples, if any */
3350                 ntups = PQntuples(res);
3351                 for (i = 0; i < ntups; i++)
3352                 {
3353                         Oid                     blobOid;
3354                         int                     loFd;
3355
3356                         blobOid = atooid(PQgetvalue(res, i, 0));
3357                         /* Open the BLOB */
3358                         loFd = lo_open(conn, blobOid, INV_READ);
3359                         if (loFd == -1)
3360                                 exit_horribly(NULL, "could not open large object %u: %s",
3361                                                           blobOid, PQerrorMessage(conn));
3362
3363                         StartBlob(fout, blobOid);
3364
3365                         /* Now read it in chunks, sending data to archive */
3366                         do
3367                         {
3368                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3369                                 if (cnt < 0)
3370                                         exit_horribly(NULL, "error reading large object %u: %s",
3371                                                                   blobOid, PQerrorMessage(conn));
3372
3373                                 WriteData(fout, buf, cnt);
3374                         } while (cnt > 0);
3375
3376                         lo_close(conn, loFd);
3377
3378                         EndBlob(fout, blobOid);
3379                 }
3380
3381                 PQclear(res);
3382         } while (ntups > 0);
3383
3384         return 1;
3385 }
3386
3387 /*
3388  * getPolicies
3389  *        get information about policies on a dumpable table.
3390  */
3391 void
3392 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3393 {
3394         PQExpBuffer query;
3395         PGresult   *res;
3396         PolicyInfo *polinfo;
3397         int                     i_oid;
3398         int                     i_tableoid;
3399         int                     i_polname;
3400         int                     i_polcmd;
3401         int                     i_polpermissive;
3402         int                     i_polroles;
3403         int                     i_polqual;
3404         int                     i_polwithcheck;
3405         int                     i,
3406                                 j,
3407                                 ntups;
3408
3409         if (fout->remoteVersion < 90500)
3410                 return;
3411
3412         query = createPQExpBuffer();
3413
3414         for (i = 0; i < numTables; i++)
3415         {
3416                 TableInfo  *tbinfo = &tblinfo[i];
3417
3418                 /* Ignore row security on tables not to be dumped */
3419                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3420                         continue;
3421
3422                 if (g_verbose)
3423                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3424                                           tbinfo->dobj.namespace->dobj.name,
3425                                           tbinfo->dobj.name);
3426
3427                 /*
3428                  * Get row security enabled information for the table. We represent
3429                  * RLS being enabled on a table by creating a PolicyInfo object with
3430                  * null polname.
3431                  */
3432                 if (tbinfo->rowsec)
3433                 {
3434                         /*
3435                          * Note: use tableoid 0 so that this object won't be mistaken for
3436                          * something that pg_depend entries apply to.
3437                          */
3438                         polinfo = pg_malloc(sizeof(PolicyInfo));
3439                         polinfo->dobj.objType = DO_POLICY;
3440                         polinfo->dobj.catId.tableoid = 0;
3441                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3442                         AssignDumpId(&polinfo->dobj);
3443                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3444                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3445                         polinfo->poltable = tbinfo;
3446                         polinfo->polname = NULL;
3447                         polinfo->polcmd = '\0';
3448                         polinfo->polpermissive = 0;
3449                         polinfo->polroles = NULL;
3450                         polinfo->polqual = NULL;
3451                         polinfo->polwithcheck = NULL;
3452                 }
3453
3454                 if (g_verbose)
3455                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3456                                           tbinfo->dobj.namespace->dobj.name,
3457                                           tbinfo->dobj.name);
3458
3459                 resetPQExpBuffer(query);
3460
3461                 /* Get the policies for the table. */
3462                 if (fout->remoteVersion >= 100000)
3463                         appendPQExpBuffer(query,
3464                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3465                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3466                                                           "   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, "
3467                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3468                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3469                                                           "FROM pg_catalog.pg_policy pol "
3470                                                           "WHERE polrelid = '%u'",
3471                                                           tbinfo->dobj.catId.oid);
3472                 else
3473                         appendPQExpBuffer(query,
3474                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3475                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3476                                                           "   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, "
3477                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3478                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3479                                                           "FROM pg_catalog.pg_policy pol "
3480                                                           "WHERE polrelid = '%u'",
3481                                                           tbinfo->dobj.catId.oid);
3482                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3483
3484                 ntups = PQntuples(res);
3485
3486                 if (ntups == 0)
3487                 {
3488                         /*
3489                          * No explicit policies to handle (only the default-deny policy,
3490                          * which is handled as part of the table definition).  Clean up
3491                          * and return.
3492                          */
3493                         PQclear(res);
3494                         continue;
3495                 }
3496
3497                 i_oid = PQfnumber(res, "oid");
3498                 i_tableoid = PQfnumber(res, "tableoid");
3499                 i_polname = PQfnumber(res, "polname");
3500                 i_polcmd = PQfnumber(res, "polcmd");
3501                 i_polpermissive = PQfnumber(res, "polpermissive");
3502                 i_polroles = PQfnumber(res, "polroles");
3503                 i_polqual = PQfnumber(res, "polqual");
3504                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3505
3506                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3507
3508                 for (j = 0; j < ntups; j++)
3509                 {
3510                         polinfo[j].dobj.objType = DO_POLICY;
3511                         polinfo[j].dobj.catId.tableoid =
3512                                 atooid(PQgetvalue(res, j, i_tableoid));
3513                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3514                         AssignDumpId(&polinfo[j].dobj);
3515                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3516                         polinfo[j].poltable = tbinfo;
3517                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3518                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3519
3520                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3521                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3522
3523                         if (PQgetisnull(res, j, i_polroles))
3524                                 polinfo[j].polroles = NULL;
3525                         else
3526                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3527
3528                         if (PQgetisnull(res, j, i_polqual))
3529                                 polinfo[j].polqual = NULL;
3530                         else
3531                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3532
3533                         if (PQgetisnull(res, j, i_polwithcheck))
3534                                 polinfo[j].polwithcheck = NULL;
3535                         else
3536                                 polinfo[j].polwithcheck
3537                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3538                 }
3539                 PQclear(res);
3540         }
3541         destroyPQExpBuffer(query);
3542 }
3543
3544 /*
3545  * dumpPolicy
3546  *        dump the definition of the given policy
3547  */
3548 static void
3549 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3550 {
3551         DumpOptions *dopt = fout->dopt;
3552         TableInfo  *tbinfo = polinfo->poltable;
3553         PQExpBuffer query;
3554         PQExpBuffer delqry;
3555         const char *cmd;
3556         char       *tag;
3557
3558         if (dopt->dataOnly)
3559                 return;
3560
3561         /*
3562          * If polname is NULL, then this record is just indicating that ROW LEVEL
3563          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3564          * ROW LEVEL SECURITY.
3565          */
3566         if (polinfo->polname == NULL)
3567         {
3568                 query = createPQExpBuffer();
3569
3570                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3571                                                   fmtQualifiedDumpable(tbinfo));
3572
3573                 /*
3574                  * We must emit the ROW SECURITY object's dependency on its table
3575                  * explicitly, because it will not match anything in pg_depend (unlike
3576                  * the case for other PolicyInfo objects).
3577                  */
3578                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3579                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3580                                                  polinfo->dobj.name,
3581                                                  polinfo->dobj.namespace->dobj.name,
3582                                                  NULL,
3583                                                  tbinfo->rolname,
3584                                                  "ROW SECURITY", SECTION_POST_DATA,
3585                                                  query->data, "", NULL,
3586                                                  &(tbinfo->dobj.dumpId), 1,
3587                                                  NULL, NULL);
3588
3589                 destroyPQExpBuffer(query);
3590                 return;
3591         }
3592
3593         if (polinfo->polcmd == '*')
3594                 cmd = "";
3595         else if (polinfo->polcmd == 'r')
3596                 cmd = " FOR SELECT";
3597         else if (polinfo->polcmd == 'a')
3598                 cmd = " FOR INSERT";
3599         else if (polinfo->polcmd == 'w')
3600                 cmd = " FOR UPDATE";
3601         else if (polinfo->polcmd == 'd')
3602                 cmd = " FOR DELETE";
3603         else
3604         {
3605                 write_msg(NULL, "unexpected policy command type: %c\n",
3606                                   polinfo->polcmd);
3607                 exit_nicely(1);
3608         }
3609
3610         query = createPQExpBuffer();
3611         delqry = createPQExpBuffer();
3612
3613         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3614
3615         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3616                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3617
3618         if (polinfo->polroles != NULL)
3619                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3620
3621         if (polinfo->polqual != NULL)
3622                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3623
3624         if (polinfo->polwithcheck != NULL)
3625                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3626
3627         appendPQExpBuffer(query, ";\n");
3628
3629         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3630         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3631
3632         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3633
3634         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3635                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3636                                          tag,
3637                                          polinfo->dobj.namespace->dobj.name,
3638                                          NULL,
3639                                          tbinfo->rolname,
3640                                          "POLICY", SECTION_POST_DATA,
3641                                          query->data, delqry->data, NULL,
3642                                          NULL, 0,
3643                                          NULL, NULL);
3644
3645         free(tag);
3646         destroyPQExpBuffer(query);
3647         destroyPQExpBuffer(delqry);
3648 }
3649
3650 /*
3651  * getPublications
3652  *        get information about publications
3653  */
3654 void
3655 getPublications(Archive *fout)
3656 {
3657         DumpOptions *dopt = fout->dopt;
3658         PQExpBuffer query;
3659         PGresult   *res;
3660         PublicationInfo *pubinfo;
3661         int                     i_tableoid;
3662         int                     i_oid;
3663         int                     i_pubname;
3664         int                     i_rolname;
3665         int                     i_puballtables;
3666         int                     i_pubinsert;
3667         int                     i_pubupdate;
3668         int                     i_pubdelete;
3669         int                     i_pubtruncate;
3670         int                     i,
3671                                 ntups;
3672
3673         if (dopt->no_publications || fout->remoteVersion < 100000)
3674                 return;
3675
3676         query = createPQExpBuffer();
3677
3678         resetPQExpBuffer(query);
3679
3680         /* Get the publications. */
3681         if (fout->remoteVersion >= 110000)
3682                 appendPQExpBuffer(query,
3683                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3684                                                   "(%s p.pubowner) AS rolname, "
3685                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3686                                                   "FROM pg_publication p",
3687                                                   username_subquery);
3688         else
3689                 appendPQExpBuffer(query,
3690                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3691                                                   "(%s p.pubowner) AS rolname, "
3692                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3693                                                   "FROM pg_publication p",
3694                                                   username_subquery);
3695
3696         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3697
3698         ntups = PQntuples(res);
3699
3700         i_tableoid = PQfnumber(res, "tableoid");
3701         i_oid = PQfnumber(res, "oid");
3702         i_pubname = PQfnumber(res, "pubname");
3703         i_rolname = PQfnumber(res, "rolname");
3704         i_puballtables = PQfnumber(res, "puballtables");
3705         i_pubinsert = PQfnumber(res, "pubinsert");
3706         i_pubupdate = PQfnumber(res, "pubupdate");
3707         i_pubdelete = PQfnumber(res, "pubdelete");
3708         i_pubtruncate = PQfnumber(res, "pubtruncate");
3709
3710         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3711
3712         for (i = 0; i < ntups; i++)
3713         {
3714                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3715                 pubinfo[i].dobj.catId.tableoid =
3716                         atooid(PQgetvalue(res, i, i_tableoid));
3717                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3718                 AssignDumpId(&pubinfo[i].dobj);
3719                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3720                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3721                 pubinfo[i].puballtables =
3722                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3723                 pubinfo[i].pubinsert =
3724                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3725                 pubinfo[i].pubupdate =
3726                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3727                 pubinfo[i].pubdelete =
3728                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3729                 pubinfo[i].pubtruncate =
3730                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3731
3732                 if (strlen(pubinfo[i].rolname) == 0)
3733                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3734                                           pubinfo[i].dobj.name);
3735
3736                 /* Decide whether we want to dump it */
3737                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3738         }
3739         PQclear(res);
3740
3741         destroyPQExpBuffer(query);
3742 }
3743
3744 /*
3745  * dumpPublication
3746  *        dump the definition of the given publication
3747  */
3748 static void
3749 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3750 {
3751         PQExpBuffer delq;
3752         PQExpBuffer query;
3753         char       *qpubname;
3754         bool            first = true;
3755
3756         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3757                 return;
3758
3759         delq = createPQExpBuffer();
3760         query = createPQExpBuffer();
3761
3762         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3763
3764         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3765                                           qpubname);
3766
3767         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3768                                           qpubname);
3769
3770         if (pubinfo->puballtables)
3771                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3772
3773         appendPQExpBufferStr(query, " WITH (publish = '");
3774         if (pubinfo->pubinsert)
3775         {
3776                 appendPQExpBufferStr(query, "insert");
3777                 first = false;
3778         }
3779
3780         if (pubinfo->pubupdate)
3781         {
3782                 if (!first)
3783                         appendPQExpBufferStr(query, ", ");
3784
3785                 appendPQExpBufferStr(query, "update");
3786                 first = false;
3787         }
3788
3789         if (pubinfo->pubdelete)
3790         {
3791                 if (!first)
3792                         appendPQExpBufferStr(query, ", ");
3793
3794                 appendPQExpBufferStr(query, "delete");
3795                 first = false;
3796         }
3797
3798         if (pubinfo->pubtruncate)
3799         {
3800                 if (!first)
3801                         appendPQExpBufferStr(query, ", ");
3802
3803                 appendPQExpBufferStr(query, "truncate");
3804                 first = false;
3805         }
3806
3807         appendPQExpBufferStr(query, "');\n");
3808
3809         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3810                                  pubinfo->dobj.name,
3811                                  NULL,
3812                                  NULL,
3813                                  pubinfo->rolname,
3814                                  "PUBLICATION", SECTION_POST_DATA,
3815                                  query->data, delq->data, NULL,
3816                                  NULL, 0,
3817                                  NULL, NULL);
3818
3819         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3820                 dumpComment(fout, "PUBLICATION", qpubname,
3821                                         NULL, pubinfo->rolname,
3822                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3823
3824         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3825                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3826                                          NULL, pubinfo->rolname,
3827                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3828
3829         destroyPQExpBuffer(delq);
3830         destroyPQExpBuffer(query);
3831         free(qpubname);
3832 }
3833
3834 /*
3835  * getPublicationTables
3836  *        get information about publication membership for dumpable tables.
3837  */
3838 void
3839 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3840 {
3841         PQExpBuffer query;
3842         PGresult   *res;
3843         PublicationRelInfo *pubrinfo;
3844         DumpOptions *dopt = fout->dopt;
3845         int                     i_tableoid;
3846         int                     i_oid;
3847         int                     i_pubname;
3848         int                     i,
3849                                 j,
3850                                 ntups;
3851
3852         if (dopt->no_publications || fout->remoteVersion < 100000)
3853                 return;
3854
3855         query = createPQExpBuffer();
3856
3857         for (i = 0; i < numTables; i++)
3858         {
3859                 TableInfo  *tbinfo = &tblinfo[i];
3860
3861                 /* Only plain tables can be aded to publications. */
3862                 if (tbinfo->relkind != RELKIND_RELATION)
3863                         continue;
3864
3865                 /*
3866                  * Ignore publication membership of tables whose definitions are not
3867                  * to be dumped.
3868                  */
3869                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3870                         continue;
3871
3872                 if (g_verbose)
3873                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3874                                           tbinfo->dobj.namespace->dobj.name,
3875                                           tbinfo->dobj.name);
3876
3877                 resetPQExpBuffer(query);
3878
3879                 /* Get the publication membership for the table. */
3880                 appendPQExpBuffer(query,
3881                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3882                                                   "FROM pg_publication_rel pr, pg_publication p "
3883                                                   "WHERE pr.prrelid = '%u'"
3884                                                   "  AND p.oid = pr.prpubid",
3885                                                   tbinfo->dobj.catId.oid);
3886                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3887
3888                 ntups = PQntuples(res);
3889
3890                 if (ntups == 0)
3891                 {
3892                         /*
3893                          * Table is not member of any publications. Clean up and return.
3894                          */
3895                         PQclear(res);
3896                         continue;
3897                 }
3898
3899                 i_tableoid = PQfnumber(res, "tableoid");
3900                 i_oid = PQfnumber(res, "oid");
3901                 i_pubname = PQfnumber(res, "pubname");
3902
3903                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3904
3905                 for (j = 0; j < ntups; j++)
3906                 {
3907                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3908                         pubrinfo[j].dobj.catId.tableoid =
3909                                 atooid(PQgetvalue(res, j, i_tableoid));
3910                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3911                         AssignDumpId(&pubrinfo[j].dobj);
3912                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3913                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3914                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3915                         pubrinfo[j].pubtable = tbinfo;
3916
3917                         /* Decide whether we want to dump it */
3918                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
3919                 }
3920                 PQclear(res);
3921         }
3922         destroyPQExpBuffer(query);
3923 }
3924
3925 /*
3926  * dumpPublicationTable
3927  *        dump the definition of the given publication table mapping
3928  */
3929 static void
3930 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
3931 {
3932         TableInfo  *tbinfo = pubrinfo->pubtable;
3933         PQExpBuffer query;
3934         char       *tag;
3935
3936         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3937                 return;
3938
3939         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
3940
3941         query = createPQExpBuffer();
3942
3943         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
3944                                           fmtId(pubrinfo->pubname));
3945         appendPQExpBuffer(query, " %s;\n",
3946                                           fmtQualifiedDumpable(tbinfo));
3947
3948         /*
3949          * There is no point in creating drop query as drop query as the drop is
3950          * done by table drop.
3951          */
3952         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
3953                                  tag,
3954                                  tbinfo->dobj.namespace->dobj.name,
3955                                  NULL,
3956                                  "",
3957                                  "PUBLICATION TABLE", SECTION_POST_DATA,
3958                                  query->data, "", NULL,
3959                                  NULL, 0,
3960                                  NULL, NULL);
3961
3962         free(tag);
3963         destroyPQExpBuffer(query);
3964 }
3965
3966 /*
3967  * Is the currently connected user a superuser?
3968  */
3969 static bool
3970 is_superuser(Archive *fout)
3971 {
3972         ArchiveHandle *AH = (ArchiveHandle *) fout;
3973         const char *val;
3974
3975         val = PQparameterStatus(AH->connection, "is_superuser");
3976
3977         if (val && strcmp(val, "on") == 0)
3978                 return true;
3979
3980         return false;
3981 }
3982
3983 /*
3984  * getSubscriptions
3985  *        get information about subscriptions
3986  */
3987 void
3988 getSubscriptions(Archive *fout)
3989 {
3990         DumpOptions *dopt = fout->dopt;
3991         PQExpBuffer query;
3992         PGresult   *res;
3993         SubscriptionInfo *subinfo;
3994         int                     i_tableoid;
3995         int                     i_oid;
3996         int                     i_subname;
3997         int                     i_rolname;
3998         int                     i_subconninfo;
3999         int                     i_subslotname;
4000         int                     i_subsynccommit;
4001         int                     i_subpublications;
4002         int                     i,
4003                                 ntups;
4004
4005         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4006                 return;
4007
4008         if (!is_superuser(fout))
4009         {
4010                 int                     n;
4011
4012                 res = ExecuteSqlQuery(fout,
4013                                                           "SELECT count(*) FROM pg_subscription "
4014                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4015                                                           "                 WHERE datname = current_database())",
4016                                                           PGRES_TUPLES_OK);
4017                 n = atoi(PQgetvalue(res, 0, 0));
4018                 if (n > 0)
4019                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4020                 PQclear(res);
4021                 return;
4022         }
4023
4024         query = createPQExpBuffer();
4025
4026         resetPQExpBuffer(query);
4027
4028         /* Get the subscriptions in current database. */
4029         appendPQExpBuffer(query,
4030                                           "SELECT s.tableoid, s.oid, s.subname,"
4031                                           "(%s s.subowner) AS rolname, "
4032                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4033                                           " s.subpublications "
4034                                           "FROM pg_subscription s "
4035                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4036                                           "                   WHERE datname = current_database())",
4037                                           username_subquery);
4038         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4039
4040         ntups = PQntuples(res);
4041
4042         i_tableoid = PQfnumber(res, "tableoid");
4043         i_oid = PQfnumber(res, "oid");
4044         i_subname = PQfnumber(res, "subname");
4045         i_rolname = PQfnumber(res, "rolname");
4046         i_subconninfo = PQfnumber(res, "subconninfo");
4047         i_subslotname = PQfnumber(res, "subslotname");
4048         i_subsynccommit = PQfnumber(res, "subsynccommit");
4049         i_subpublications = PQfnumber(res, "subpublications");
4050
4051         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4052
4053         for (i = 0; i < ntups; i++)
4054         {
4055                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4056                 subinfo[i].dobj.catId.tableoid =
4057                         atooid(PQgetvalue(res, i, i_tableoid));
4058                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4059                 AssignDumpId(&subinfo[i].dobj);
4060                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4061                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4062                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4063                 if (PQgetisnull(res, i, i_subslotname))
4064                         subinfo[i].subslotname = NULL;
4065                 else
4066                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4067                 subinfo[i].subsynccommit =
4068                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4069                 subinfo[i].subpublications =
4070                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4071
4072                 if (strlen(subinfo[i].rolname) == 0)
4073                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4074                                           subinfo[i].dobj.name);
4075
4076                 /* Decide whether we want to dump it */
4077                 selectDumpableObject(&(subinfo[i].dobj), fout);
4078         }
4079         PQclear(res);
4080
4081         destroyPQExpBuffer(query);
4082 }
4083
4084 /*
4085  * dumpSubscription
4086  *        dump the definition of the given subscription
4087  */
4088 static void
4089 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4090 {
4091         PQExpBuffer delq;
4092         PQExpBuffer query;
4093         PQExpBuffer publications;
4094         char       *qsubname;
4095         char      **pubnames = NULL;
4096         int                     npubnames = 0;
4097         int                     i;
4098
4099         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4100                 return;
4101
4102         delq = createPQExpBuffer();
4103         query = createPQExpBuffer();
4104
4105         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4106
4107         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4108                                           qsubname);
4109
4110         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4111                                           qsubname);
4112         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4113
4114         /* Build list of quoted publications and append them to query. */
4115         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4116         {
4117                 write_msg(NULL,
4118                                   "WARNING: could not parse subpublications array\n");
4119                 if (pubnames)
4120                         free(pubnames);
4121                 pubnames = NULL;
4122                 npubnames = 0;
4123         }
4124
4125         publications = createPQExpBuffer();
4126         for (i = 0; i < npubnames; i++)
4127         {
4128                 if (i > 0)
4129                         appendPQExpBufferStr(publications, ", ");
4130
4131                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4132         }
4133
4134         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4135         if (subinfo->subslotname)
4136                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4137         else
4138                 appendPQExpBufferStr(query, "NONE");
4139
4140         if (strcmp(subinfo->subsynccommit, "off") != 0)
4141                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4142
4143         appendPQExpBufferStr(query, ");\n");
4144
4145         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4146                                  subinfo->dobj.name,
4147                                  NULL,
4148                                  NULL,
4149                                  subinfo->rolname,
4150                                  "SUBSCRIPTION", SECTION_POST_DATA,
4151                                  query->data, delq->data, NULL,
4152                                  NULL, 0,
4153                                  NULL, NULL);
4154
4155         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4156                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4157                                         NULL, subinfo->rolname,
4158                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4159
4160         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4161                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4162                                          NULL, subinfo->rolname,
4163                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4164
4165         destroyPQExpBuffer(publications);
4166         if (pubnames)
4167                 free(pubnames);
4168
4169         destroyPQExpBuffer(delq);
4170         destroyPQExpBuffer(query);
4171         free(qsubname);
4172 }
4173
4174 static void
4175 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4176                                                                                  PQExpBuffer upgrade_buffer,
4177                                                                                  Oid pg_type_oid,
4178                                                                                  bool force_array_type)
4179 {
4180         PQExpBuffer upgrade_query = createPQExpBuffer();
4181         PGresult   *res;
4182         Oid                     pg_type_array_oid;
4183
4184         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4185         appendPQExpBuffer(upgrade_buffer,
4186                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4187                                           pg_type_oid);
4188
4189         /* we only support old >= 8.3 for binary upgrades */
4190         appendPQExpBuffer(upgrade_query,
4191                                           "SELECT typarray "
4192                                           "FROM pg_catalog.pg_type "
4193                                           "WHERE oid = '%u'::pg_catalog.oid;",
4194                                           pg_type_oid);
4195
4196         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4197
4198         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4199
4200         PQclear(res);
4201
4202         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4203         {
4204                 /*
4205                  * If the old version didn't assign an array type, but the new version
4206                  * does, we must select an unused type OID to assign.  This currently
4207                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4208                  *
4209                  * Note: local state here is kind of ugly, but we must have some,
4210                  * since we mustn't choose the same unused OID more than once.
4211                  */
4212                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4213                 bool            is_dup;
4214
4215                 do
4216                 {
4217                         ++next_possible_free_oid;
4218                         printfPQExpBuffer(upgrade_query,
4219                                                           "SELECT EXISTS(SELECT 1 "
4220                                                           "FROM pg_catalog.pg_type "
4221                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4222                                                           next_possible_free_oid);
4223                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4224                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4225                         PQclear(res);
4226                 } while (is_dup);
4227
4228                 pg_type_array_oid = next_possible_free_oid;
4229         }
4230
4231         if (OidIsValid(pg_type_array_oid))
4232         {
4233                 appendPQExpBufferStr(upgrade_buffer,
4234                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4235                 appendPQExpBuffer(upgrade_buffer,
4236                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4237                                                   pg_type_array_oid);
4238         }
4239
4240         destroyPQExpBuffer(upgrade_query);
4241 }
4242
4243 static bool
4244 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4245                                                                                 PQExpBuffer upgrade_buffer,
4246                                                                                 Oid pg_rel_oid)
4247 {
4248         PQExpBuffer upgrade_query = createPQExpBuffer();
4249         PGresult   *upgrade_res;
4250         Oid                     pg_type_oid;
4251         bool            toast_set = false;
4252
4253         /* we only support old >= 8.3 for binary upgrades */
4254         appendPQExpBuffer(upgrade_query,
4255                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4256                                           "FROM pg_catalog.pg_class c "
4257                                           "LEFT JOIN pg_catalog.pg_class t ON "
4258                                           "  (c.reltoastrelid = t.oid) "
4259                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4260                                           pg_rel_oid);
4261
4262         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4263
4264         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4265
4266         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4267                                                                                          pg_type_oid, false);
4268
4269         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4270         {
4271                 /* Toast tables do not have pg_type array rows */
4272                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4273                                                                                                                   PQfnumber(upgrade_res, "trel")));
4274
4275                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4276                 appendPQExpBuffer(upgrade_buffer,
4277                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4278                                                   pg_type_toast_oid);
4279
4280                 toast_set = true;
4281         }
4282
4283         PQclear(upgrade_res);
4284         destroyPQExpBuffer(upgrade_query);
4285
4286         return toast_set;
4287 }
4288
4289 static void
4290 binary_upgrade_set_pg_class_oids(Archive *fout,
4291                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4292                                                                  bool is_index)
4293 {
4294         PQExpBuffer upgrade_query = createPQExpBuffer();
4295         PGresult   *upgrade_res;
4296         Oid                     pg_class_reltoastrelid;
4297         Oid                     pg_index_indexrelid;
4298
4299         appendPQExpBuffer(upgrade_query,
4300                                           "SELECT c.reltoastrelid, i.indexrelid "
4301                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4302                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4303                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4304                                           pg_class_oid);
4305
4306         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4307
4308         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4309         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4310
4311         appendPQExpBufferStr(upgrade_buffer,
4312                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4313
4314         if (!is_index)
4315         {
4316                 appendPQExpBuffer(upgrade_buffer,
4317                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4318                                                   pg_class_oid);
4319                 /* only tables have toast tables, not indexes */
4320                 if (OidIsValid(pg_class_reltoastrelid))
4321                 {
4322                         /*
4323                          * One complexity is that the table definition might not require
4324                          * the creation of a TOAST table, and the TOAST table might have
4325                          * been created long after table creation, when the table was
4326                          * loaded with wide data.  By setting the TOAST oid we force
4327                          * creation of the TOAST heap and TOAST index by the backend so we
4328                          * can cleanly copy the files during binary upgrade.
4329                          */
4330
4331                         appendPQExpBuffer(upgrade_buffer,
4332                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4333                                                           pg_class_reltoastrelid);
4334
4335                         /* every toast table has an index */
4336                         appendPQExpBuffer(upgrade_buffer,
4337                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4338                                                           pg_index_indexrelid);
4339                 }
4340         }
4341         else
4342                 appendPQExpBuffer(upgrade_buffer,
4343                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4344                                                   pg_class_oid);
4345
4346         appendPQExpBufferChar(upgrade_buffer, '\n');
4347
4348         PQclear(upgrade_res);
4349         destroyPQExpBuffer(upgrade_query);
4350 }
4351
4352 /*
4353  * If the DumpableObject is a member of an extension, add a suitable
4354  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4355  *
4356  * For somewhat historical reasons, objname should already be quoted,
4357  * but not objnamespace (if any).
4358  */
4359 static void
4360 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4361                                                                 DumpableObject *dobj,
4362                                                                 const char *objtype,
4363                                                                 const char *objname,
4364                                                                 const char *objnamespace)
4365 {
4366         DumpableObject *extobj = NULL;
4367         int                     i;
4368
4369         if (!dobj->ext_member)
4370                 return;
4371
4372         /*
4373          * Find the parent extension.  We could avoid this search if we wanted to
4374          * add a link field to DumpableObject, but the space costs of that would
4375          * be considerable.  We assume that member objects could only have a
4376          * direct dependency on their own extension, not any others.
4377          */
4378         for (i = 0; i < dobj->nDeps; i++)
4379         {
4380                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4381                 if (extobj && extobj->objType == DO_EXTENSION)
4382                         break;
4383                 extobj = NULL;
4384         }
4385         if (extobj == NULL)
4386                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4387                                           objtype, objname);
4388
4389         appendPQExpBufferStr(upgrade_buffer,
4390                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4391         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4392                                           fmtId(extobj->name),
4393                                           objtype);
4394         if (objnamespace && *objnamespace)
4395                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4396         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4397 }
4398
4399 /*
4400  * getNamespaces:
4401  *        read all namespaces in the system catalogs and return them in the
4402  * NamespaceInfo* structure
4403  *
4404  *      numNamespaces is set to the number of namespaces read in
4405  */
4406 NamespaceInfo *
4407 getNamespaces(Archive *fout, int *numNamespaces)
4408 {
4409         DumpOptions *dopt = fout->dopt;
4410         PGresult   *res;
4411         int                     ntups;
4412         int                     i;
4413         PQExpBuffer query;
4414         NamespaceInfo *nsinfo;
4415         int                     i_tableoid;
4416         int                     i_oid;
4417         int                     i_nspname;
4418         int                     i_rolname;
4419         int                     i_nspacl;
4420         int                     i_rnspacl;
4421         int                     i_initnspacl;
4422         int                     i_initrnspacl;
4423
4424         query = createPQExpBuffer();
4425
4426         /*
4427          * we fetch all namespaces including system ones, so that every object we
4428          * read in can be linked to a containing namespace.
4429          */
4430         if (fout->remoteVersion >= 90600)
4431         {
4432                 PQExpBuffer acl_subquery = createPQExpBuffer();
4433                 PQExpBuffer racl_subquery = createPQExpBuffer();
4434                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4435                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4436
4437                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4438                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4439                                                 dopt->binary_upgrade);
4440
4441                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4442                                                   "(%s nspowner) AS rolname, "
4443                                                   "%s as nspacl, "
4444                                                   "%s as rnspacl, "
4445                                                   "%s as initnspacl, "
4446                                                   "%s as initrnspacl "
4447                                                   "FROM pg_namespace n "
4448                                                   "LEFT JOIN pg_init_privs pip "
4449                                                   "ON (n.oid = pip.objoid "
4450                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4451                                                   "AND pip.objsubid = 0",
4452                                                   username_subquery,
4453                                                   acl_subquery->data,
4454                                                   racl_subquery->data,
4455                                                   init_acl_subquery->data,
4456                                                   init_racl_subquery->data);
4457
4458                 appendPQExpBuffer(query, ") ");
4459
4460                 destroyPQExpBuffer(acl_subquery);
4461                 destroyPQExpBuffer(racl_subquery);
4462                 destroyPQExpBuffer(init_acl_subquery);
4463                 destroyPQExpBuffer(init_racl_subquery);
4464         }
4465         else
4466                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4467                                                   "(%s nspowner) AS rolname, "
4468                                                   "nspacl, NULL as rnspacl, "
4469                                                   "NULL AS initnspacl, NULL as initrnspacl "
4470                                                   "FROM pg_namespace",
4471                                                   username_subquery);
4472
4473         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4474
4475         ntups = PQntuples(res);
4476
4477         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4478
4479         i_tableoid = PQfnumber(res, "tableoid");
4480         i_oid = PQfnumber(res, "oid");
4481         i_nspname = PQfnumber(res, "nspname");
4482         i_rolname = PQfnumber(res, "rolname");
4483         i_nspacl = PQfnumber(res, "nspacl");
4484         i_rnspacl = PQfnumber(res, "rnspacl");
4485         i_initnspacl = PQfnumber(res, "initnspacl");
4486         i_initrnspacl = PQfnumber(res, "initrnspacl");
4487
4488         for (i = 0; i < ntups; i++)
4489         {
4490                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4491                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4492                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4493                 AssignDumpId(&nsinfo[i].dobj);
4494                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4495                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4496                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4497                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4498                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4499                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4500
4501                 /* Decide whether to dump this namespace */
4502                 selectDumpableNamespace(&nsinfo[i], fout);
4503
4504                 /*
4505                  * Do not try to dump ACL if the ACL is empty or the default.
4506                  *
4507                  * This is useful because, for some schemas/objects, the only
4508                  * component we are going to try and dump is the ACL and if we can
4509                  * remove that then 'dump' goes to zero/false and we don't consider
4510                  * this object for dumping at all later on.
4511                  */
4512                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4513                         PQgetisnull(res, i, i_initnspacl) &&
4514                         PQgetisnull(res, i, i_initrnspacl))
4515                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4516
4517                 if (strlen(nsinfo[i].rolname) == 0)
4518                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4519                                           nsinfo[i].dobj.name);
4520         }
4521
4522         PQclear(res);
4523         destroyPQExpBuffer(query);
4524
4525         *numNamespaces = ntups;
4526
4527         return nsinfo;
4528 }
4529
4530 /*
4531  * findNamespace:
4532  *              given a namespace OID, look up the info read by getNamespaces
4533  */
4534 static NamespaceInfo *
4535 findNamespace(Archive *fout, Oid nsoid)
4536 {
4537         NamespaceInfo *nsinfo;
4538
4539         nsinfo = findNamespaceByOid(nsoid);
4540         if (nsinfo == NULL)
4541                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4542         return nsinfo;
4543 }
4544
4545 /*
4546  * getExtensions:
4547  *        read all extensions in the system catalogs and return them in the
4548  * ExtensionInfo* structure
4549  *
4550  *      numExtensions is set to the number of extensions read in
4551  */
4552 ExtensionInfo *
4553 getExtensions(Archive *fout, int *numExtensions)
4554 {
4555         DumpOptions *dopt = fout->dopt;
4556         PGresult   *res;
4557         int                     ntups;
4558         int                     i;
4559         PQExpBuffer query;
4560         ExtensionInfo *extinfo;
4561         int                     i_tableoid;
4562         int                     i_oid;
4563         int                     i_extname;
4564         int                     i_nspname;
4565         int                     i_extrelocatable;
4566         int                     i_extversion;
4567         int                     i_extconfig;
4568         int                     i_extcondition;
4569
4570         /*
4571          * Before 9.1, there are no extensions.
4572          */
4573         if (fout->remoteVersion < 90100)
4574         {
4575                 *numExtensions = 0;
4576                 return NULL;
4577         }
4578
4579         query = createPQExpBuffer();
4580
4581         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4582                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4583                                                  "FROM pg_extension x "
4584                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4585
4586         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4587
4588         ntups = PQntuples(res);
4589
4590         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4591
4592         i_tableoid = PQfnumber(res, "tableoid");
4593         i_oid = PQfnumber(res, "oid");
4594         i_extname = PQfnumber(res, "extname");
4595         i_nspname = PQfnumber(res, "nspname");
4596         i_extrelocatable = PQfnumber(res, "extrelocatable");
4597         i_extversion = PQfnumber(res, "extversion");
4598         i_extconfig = PQfnumber(res, "extconfig");
4599         i_extcondition = PQfnumber(res, "extcondition");
4600
4601         for (i = 0; i < ntups; i++)
4602         {
4603                 extinfo[i].dobj.objType = DO_EXTENSION;
4604                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4605                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4606                 AssignDumpId(&extinfo[i].dobj);
4607                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4608                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4609                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4610                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4611                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4612                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4613
4614                 /* Decide whether we want to dump it */
4615                 selectDumpableExtension(&(extinfo[i]), dopt);
4616         }
4617
4618         PQclear(res);
4619         destroyPQExpBuffer(query);
4620
4621         *numExtensions = ntups;
4622
4623         return extinfo;
4624 }
4625
4626 /*
4627  * getTypes:
4628  *        read all types in the system catalogs and return them in the
4629  * TypeInfo* structure
4630  *
4631  *      numTypes is set to the number of types read in
4632  *
4633  * NB: this must run after getFuncs() because we assume we can do
4634  * findFuncByOid().
4635  */
4636 TypeInfo *
4637 getTypes(Archive *fout, int *numTypes)
4638 {
4639         DumpOptions *dopt = fout->dopt;
4640         PGresult   *res;
4641         int                     ntups;
4642         int                     i;
4643         PQExpBuffer query = createPQExpBuffer();
4644         TypeInfo   *tyinfo;
4645         ShellTypeInfo *stinfo;
4646         int                     i_tableoid;
4647         int                     i_oid;
4648         int                     i_typname;
4649         int                     i_typnamespace;
4650         int                     i_typacl;
4651         int                     i_rtypacl;
4652         int                     i_inittypacl;
4653         int                     i_initrtypacl;
4654         int                     i_rolname;
4655         int                     i_typelem;
4656         int                     i_typrelid;
4657         int                     i_typrelkind;
4658         int                     i_typtype;
4659         int                     i_typisdefined;
4660         int                     i_isarray;
4661
4662         /*
4663          * we include even the built-in types because those may be used as array
4664          * elements by user-defined types
4665          *
4666          * we filter out the built-in types when we dump out the types
4667          *
4668          * same approach for undefined (shell) types and array types
4669          *
4670          * Note: as of 8.3 we can reliably detect whether a type is an
4671          * auto-generated array type by checking the element type's typarray.
4672          * (Before that the test is capable of generating false positives.) We
4673          * still check for name beginning with '_', though, so as to avoid the
4674          * cost of the subselect probe for all standard types.  This would have to
4675          * be revisited if the backend ever allows renaming of array types.
4676          */
4677
4678         if (fout->remoteVersion >= 90600)
4679         {
4680                 PQExpBuffer acl_subquery = createPQExpBuffer();
4681                 PQExpBuffer racl_subquery = createPQExpBuffer();
4682                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4683                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4684
4685                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4686                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4687                                                 dopt->binary_upgrade);
4688
4689                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4690                                                   "t.typnamespace, "
4691                                                   "%s AS typacl, "
4692                                                   "%s AS rtypacl, "
4693                                                   "%s AS inittypacl, "
4694                                                   "%s AS initrtypacl, "
4695                                                   "(%s t.typowner) AS rolname, "
4696                                                   "t.typelem, t.typrelid, "
4697                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4698                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4699                                                   "t.typtype, t.typisdefined, "
4700                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4701                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4702                                                   "FROM pg_type t "
4703                                                   "LEFT JOIN pg_init_privs pip ON "
4704                                                   "(t.oid = pip.objoid "
4705                                                   "AND pip.classoid = 'pg_type'::regclass "
4706                                                   "AND pip.objsubid = 0) ",
4707                                                   acl_subquery->data,
4708                                                   racl_subquery->data,
4709                                                   initacl_subquery->data,
4710                                                   initracl_subquery->data,
4711                                                   username_subquery);
4712
4713                 destroyPQExpBuffer(acl_subquery);
4714                 destroyPQExpBuffer(racl_subquery);
4715                 destroyPQExpBuffer(initacl_subquery);
4716                 destroyPQExpBuffer(initracl_subquery);
4717         }
4718         else if (fout->remoteVersion >= 90200)
4719         {
4720                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4721                                                   "typnamespace, typacl, NULL as rtypacl, "
4722                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4723                                                   "(%s typowner) AS rolname, "
4724                                                   "typelem, typrelid, "
4725                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4726                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4727                                                   "typtype, typisdefined, "
4728                                                   "typname[0] = '_' AND typelem != 0 AND "
4729                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4730                                                   "FROM pg_type",
4731                                                   username_subquery);
4732         }
4733         else if (fout->remoteVersion >= 80300)
4734         {
4735                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4736                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4737                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4738                                                   "(%s typowner) AS rolname, "
4739                                                   "typelem, typrelid, "
4740                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4741                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4742                                                   "typtype, typisdefined, "
4743                                                   "typname[0] = '_' AND typelem != 0 AND "
4744                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4745                                                   "FROM pg_type",
4746                                                   username_subquery);
4747         }
4748         else
4749         {
4750                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4751                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4752                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4753                                                   "(%s typowner) AS rolname, "
4754                                                   "typelem, typrelid, "
4755                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4756                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4757                                                   "typtype, typisdefined, "
4758                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4759                                                   "FROM pg_type",
4760                                                   username_subquery);
4761         }
4762
4763         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4764
4765         ntups = PQntuples(res);
4766
4767         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4768
4769         i_tableoid = PQfnumber(res, "tableoid");
4770         i_oid = PQfnumber(res, "oid");
4771         i_typname = PQfnumber(res, "typname");
4772         i_typnamespace = PQfnumber(res, "typnamespace");
4773         i_typacl = PQfnumber(res, "typacl");
4774         i_rtypacl = PQfnumber(res, "rtypacl");
4775         i_inittypacl = PQfnumber(res, "inittypacl");
4776         i_initrtypacl = PQfnumber(res, "initrtypacl");
4777         i_rolname = PQfnumber(res, "rolname");
4778         i_typelem = PQfnumber(res, "typelem");
4779         i_typrelid = PQfnumber(res, "typrelid");
4780         i_typrelkind = PQfnumber(res, "typrelkind");
4781         i_typtype = PQfnumber(res, "typtype");
4782         i_typisdefined = PQfnumber(res, "typisdefined");
4783         i_isarray = PQfnumber(res, "isarray");
4784
4785         for (i = 0; i < ntups; i++)
4786         {
4787                 tyinfo[i].dobj.objType = DO_TYPE;
4788                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4789                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4790                 AssignDumpId(&tyinfo[i].dobj);
4791                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4792                 tyinfo[i].dobj.namespace =
4793                         findNamespace(fout,
4794                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4795                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4796                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4797                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4798                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4799                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4800                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4801                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4802                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4803                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4804                 tyinfo[i].shellType = NULL;
4805
4806                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4807                         tyinfo[i].isDefined = true;
4808                 else
4809                         tyinfo[i].isDefined = false;
4810
4811                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4812                         tyinfo[i].isArray = true;
4813                 else
4814                         tyinfo[i].isArray = false;
4815
4816                 /* Decide whether we want to dump it */
4817                 selectDumpableType(&tyinfo[i], fout);
4818
4819                 /* Do not try to dump ACL if no ACL exists. */
4820                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4821                         PQgetisnull(res, i, i_inittypacl) &&
4822                         PQgetisnull(res, i, i_initrtypacl))
4823                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4824
4825                 /*
4826                  * If it's a domain, fetch info about its constraints, if any
4827                  */
4828                 tyinfo[i].nDomChecks = 0;
4829                 tyinfo[i].domChecks = NULL;
4830                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4831                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4832                         getDomainConstraints(fout, &(tyinfo[i]));
4833
4834                 /*
4835                  * If it's a base type, make a DumpableObject representing a shell
4836                  * definition of the type.  We will need to dump that ahead of the I/O
4837                  * functions for the type.  Similarly, range types need a shell
4838                  * definition in case they have a canonicalize function.
4839                  *
4840                  * Note: the shell type doesn't have a catId.  You might think it
4841                  * should copy the base type's catId, but then it might capture the
4842                  * pg_depend entries for the type, which we don't want.
4843                  */
4844                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4845                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4846                          tyinfo[i].typtype == TYPTYPE_RANGE))
4847                 {
4848                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4849                         stinfo->dobj.objType = DO_SHELL_TYPE;
4850                         stinfo->dobj.catId = nilCatalogId;
4851                         AssignDumpId(&stinfo->dobj);
4852                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4853                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4854                         stinfo->baseType = &(tyinfo[i]);
4855                         tyinfo[i].shellType = stinfo;
4856
4857                         /*
4858                          * Initially mark the shell type as not to be dumped.  We'll only
4859                          * dump it if the I/O or canonicalize functions need to be dumped;
4860                          * this is taken care of while sorting dependencies.
4861                          */
4862                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4863                 }
4864
4865                 if (strlen(tyinfo[i].rolname) == 0)
4866                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4867                                           tyinfo[i].dobj.name);
4868         }
4869
4870         *numTypes = ntups;
4871
4872         PQclear(res);
4873
4874         destroyPQExpBuffer(query);
4875
4876         return tyinfo;
4877 }
4878
4879 /*
4880  * getOperators:
4881  *        read all operators in the system catalogs and return them in the
4882  * OprInfo* structure
4883  *
4884  *      numOprs is set to the number of operators read in
4885  */
4886 OprInfo *
4887 getOperators(Archive *fout, int *numOprs)
4888 {
4889         PGresult   *res;
4890         int                     ntups;
4891         int                     i;
4892         PQExpBuffer query = createPQExpBuffer();
4893         OprInfo    *oprinfo;
4894         int                     i_tableoid;
4895         int                     i_oid;
4896         int                     i_oprname;
4897         int                     i_oprnamespace;
4898         int                     i_rolname;
4899         int                     i_oprkind;
4900         int                     i_oprcode;
4901
4902         /*
4903          * find all operators, including builtin operators; we filter out
4904          * system-defined operators at dump-out time.
4905          */
4906
4907         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4908                                           "oprnamespace, "
4909                                           "(%s oprowner) AS rolname, "
4910                                           "oprkind, "
4911                                           "oprcode::oid AS oprcode "
4912                                           "FROM pg_operator",
4913                                           username_subquery);
4914
4915         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4916
4917         ntups = PQntuples(res);
4918         *numOprs = ntups;
4919
4920         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4921
4922         i_tableoid = PQfnumber(res, "tableoid");
4923         i_oid = PQfnumber(res, "oid");
4924         i_oprname = PQfnumber(res, "oprname");
4925         i_oprnamespace = PQfnumber(res, "oprnamespace");
4926         i_rolname = PQfnumber(res, "rolname");
4927         i_oprkind = PQfnumber(res, "oprkind");
4928         i_oprcode = PQfnumber(res, "oprcode");
4929
4930         for (i = 0; i < ntups; i++)
4931         {
4932                 oprinfo[i].dobj.objType = DO_OPERATOR;
4933                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4934                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4935                 AssignDumpId(&oprinfo[i].dobj);
4936                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4937                 oprinfo[i].dobj.namespace =
4938                         findNamespace(fout,
4939                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
4940                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4941                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4942                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4943
4944                 /* Decide whether we want to dump it */
4945                 selectDumpableObject(&(oprinfo[i].dobj), fout);
4946
4947                 /* Operators do not currently have ACLs. */
4948                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4949
4950                 if (strlen(oprinfo[i].rolname) == 0)
4951                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4952                                           oprinfo[i].dobj.name);
4953         }
4954
4955         PQclear(res);
4956
4957         destroyPQExpBuffer(query);
4958
4959         return oprinfo;
4960 }
4961
4962 /*
4963  * getCollations:
4964  *        read all collations in the system catalogs and return them in the
4965  * CollInfo* structure
4966  *
4967  *      numCollations is set to the number of collations read in
4968  */
4969 CollInfo *
4970 getCollations(Archive *fout, int *numCollations)
4971 {
4972         PGresult   *res;
4973         int                     ntups;
4974         int                     i;
4975         PQExpBuffer query;
4976         CollInfo   *collinfo;
4977         int                     i_tableoid;
4978         int                     i_oid;
4979         int                     i_collname;
4980         int                     i_collnamespace;
4981         int                     i_rolname;
4982
4983         /* Collations didn't exist pre-9.1 */
4984         if (fout->remoteVersion < 90100)
4985         {
4986                 *numCollations = 0;
4987                 return NULL;
4988         }
4989
4990         query = createPQExpBuffer();
4991
4992         /*
4993          * find all collations, including builtin collations; we filter out
4994          * system-defined collations at dump-out time.
4995          */
4996
4997         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
4998                                           "collnamespace, "
4999                                           "(%s collowner) AS rolname "
5000                                           "FROM pg_collation",
5001                                           username_subquery);
5002
5003         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5004
5005         ntups = PQntuples(res);
5006         *numCollations = ntups;
5007
5008         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5009
5010         i_tableoid = PQfnumber(res, "tableoid");
5011         i_oid = PQfnumber(res, "oid");
5012         i_collname = PQfnumber(res, "collname");
5013         i_collnamespace = PQfnumber(res, "collnamespace");
5014         i_rolname = PQfnumber(res, "rolname");
5015
5016         for (i = 0; i < ntups; i++)
5017         {
5018                 collinfo[i].dobj.objType = DO_COLLATION;
5019                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5020                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5021                 AssignDumpId(&collinfo[i].dobj);
5022                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5023                 collinfo[i].dobj.namespace =
5024                         findNamespace(fout,
5025                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5026                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5027
5028                 /* Decide whether we want to dump it */
5029                 selectDumpableObject(&(collinfo[i].dobj), fout);
5030
5031                 /* Collations do not currently have ACLs. */
5032                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5033         }
5034
5035         PQclear(res);
5036
5037         destroyPQExpBuffer(query);
5038
5039         return collinfo;
5040 }
5041
5042 /*
5043  * getConversions:
5044  *        read all conversions in the system catalogs and return them in the
5045  * ConvInfo* structure
5046  *
5047  *      numConversions is set to the number of conversions read in
5048  */
5049 ConvInfo *
5050 getConversions(Archive *fout, int *numConversions)
5051 {
5052         PGresult   *res;
5053         int                     ntups;
5054         int                     i;
5055         PQExpBuffer query;
5056         ConvInfo   *convinfo;
5057         int                     i_tableoid;
5058         int                     i_oid;
5059         int                     i_conname;
5060         int                     i_connamespace;
5061         int                     i_rolname;
5062
5063         query = createPQExpBuffer();
5064
5065         /*
5066          * find all conversions, including builtin conversions; we filter out
5067          * system-defined conversions at dump-out time.
5068          */
5069
5070         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5071                                           "connamespace, "
5072                                           "(%s conowner) AS rolname "
5073                                           "FROM pg_conversion",
5074                                           username_subquery);
5075
5076         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5077
5078         ntups = PQntuples(res);
5079         *numConversions = ntups;
5080
5081         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5082
5083         i_tableoid = PQfnumber(res, "tableoid");
5084         i_oid = PQfnumber(res, "oid");
5085         i_conname = PQfnumber(res, "conname");
5086         i_connamespace = PQfnumber(res, "connamespace");
5087         i_rolname = PQfnumber(res, "rolname");
5088
5089         for (i = 0; i < ntups; i++)
5090         {
5091                 convinfo[i].dobj.objType = DO_CONVERSION;
5092                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5093                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5094                 AssignDumpId(&convinfo[i].dobj);
5095                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5096                 convinfo[i].dobj.namespace =
5097                         findNamespace(fout,
5098                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5099                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5100
5101                 /* Decide whether we want to dump it */
5102                 selectDumpableObject(&(convinfo[i].dobj), fout);
5103
5104                 /* Conversions do not currently have ACLs. */
5105                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5106         }
5107
5108         PQclear(res);
5109
5110         destroyPQExpBuffer(query);
5111
5112         return convinfo;
5113 }
5114
5115 /*
5116  * getAccessMethods:
5117  *        read all user-defined access methods in the system catalogs and return
5118  *        them in the AccessMethodInfo* structure
5119  *
5120  *      numAccessMethods is set to the number of access methods read in
5121  */
5122 AccessMethodInfo *
5123 getAccessMethods(Archive *fout, int *numAccessMethods)
5124 {
5125         PGresult   *res;
5126         int                     ntups;
5127         int                     i;
5128         PQExpBuffer query;
5129         AccessMethodInfo *aminfo;
5130         int                     i_tableoid;
5131         int                     i_oid;
5132         int                     i_amname;
5133         int                     i_amhandler;
5134         int                     i_amtype;
5135
5136         /* Before 9.6, there are no user-defined access methods */
5137         if (fout->remoteVersion < 90600)
5138         {
5139                 *numAccessMethods = 0;
5140                 return NULL;
5141         }
5142
5143         query = createPQExpBuffer();
5144
5145         /* Select all access methods from pg_am table */
5146         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5147                                           "amhandler::pg_catalog.regproc AS amhandler "
5148                                           "FROM pg_am");
5149
5150         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5151
5152         ntups = PQntuples(res);
5153         *numAccessMethods = ntups;
5154
5155         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5156
5157         i_tableoid = PQfnumber(res, "tableoid");
5158         i_oid = PQfnumber(res, "oid");
5159         i_amname = PQfnumber(res, "amname");
5160         i_amhandler = PQfnumber(res, "amhandler");
5161         i_amtype = PQfnumber(res, "amtype");
5162
5163         for (i = 0; i < ntups; i++)
5164         {
5165                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5166                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5167                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5168                 AssignDumpId(&aminfo[i].dobj);
5169                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5170                 aminfo[i].dobj.namespace = NULL;
5171                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5172                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5173
5174                 /* Decide whether we want to dump it */
5175                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5176
5177                 /* Access methods do not currently have ACLs. */
5178                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5179         }
5180
5181         PQclear(res);
5182
5183         destroyPQExpBuffer(query);
5184
5185         return aminfo;
5186 }
5187
5188
5189 /*
5190  * getOpclasses:
5191  *        read all opclasses in the system catalogs and return them in the
5192  * OpclassInfo* structure
5193  *
5194  *      numOpclasses is set to the number of opclasses read in
5195  */
5196 OpclassInfo *
5197 getOpclasses(Archive *fout, int *numOpclasses)
5198 {
5199         PGresult   *res;
5200         int                     ntups;
5201         int                     i;
5202         PQExpBuffer query = createPQExpBuffer();
5203         OpclassInfo *opcinfo;
5204         int                     i_tableoid;
5205         int                     i_oid;
5206         int                     i_opcname;
5207         int                     i_opcnamespace;
5208         int                     i_rolname;
5209
5210         /*
5211          * find all opclasses, including builtin opclasses; we filter out
5212          * system-defined opclasses at dump-out time.
5213          */
5214
5215         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5216                                           "opcnamespace, "
5217                                           "(%s opcowner) AS rolname "
5218                                           "FROM pg_opclass",
5219                                           username_subquery);
5220
5221         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5222
5223         ntups = PQntuples(res);
5224         *numOpclasses = ntups;
5225
5226         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5227
5228         i_tableoid = PQfnumber(res, "tableoid");
5229         i_oid = PQfnumber(res, "oid");
5230         i_opcname = PQfnumber(res, "opcname");
5231         i_opcnamespace = PQfnumber(res, "opcnamespace");
5232         i_rolname = PQfnumber(res, "rolname");
5233
5234         for (i = 0; i < ntups; i++)
5235         {
5236                 opcinfo[i].dobj.objType = DO_OPCLASS;
5237                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5238                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5239                 AssignDumpId(&opcinfo[i].dobj);
5240                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5241                 opcinfo[i].dobj.namespace =
5242                         findNamespace(fout,
5243                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5244                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5245
5246                 /* Decide whether we want to dump it */
5247                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5248
5249                 /* Op Classes do not currently have ACLs. */
5250                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5251
5252                 if (strlen(opcinfo[i].rolname) == 0)
5253                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5254                                           opcinfo[i].dobj.name);
5255         }
5256
5257         PQclear(res);
5258
5259         destroyPQExpBuffer(query);
5260
5261         return opcinfo;
5262 }
5263
5264 /*
5265  * getOpfamilies:
5266  *        read all opfamilies in the system catalogs and return them in the
5267  * OpfamilyInfo* structure
5268  *
5269  *      numOpfamilies is set to the number of opfamilies read in
5270  */
5271 OpfamilyInfo *
5272 getOpfamilies(Archive *fout, int *numOpfamilies)
5273 {
5274         PGresult   *res;
5275         int                     ntups;
5276         int                     i;
5277         PQExpBuffer query;
5278         OpfamilyInfo *opfinfo;
5279         int                     i_tableoid;
5280         int                     i_oid;
5281         int                     i_opfname;
5282         int                     i_opfnamespace;
5283         int                     i_rolname;
5284
5285         /* Before 8.3, there is no separate concept of opfamilies */
5286         if (fout->remoteVersion < 80300)
5287         {
5288                 *numOpfamilies = 0;
5289                 return NULL;
5290         }
5291
5292         query = createPQExpBuffer();
5293
5294         /*
5295          * find all opfamilies, including builtin opfamilies; we filter out
5296          * system-defined opfamilies at dump-out time.
5297          */
5298
5299         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5300                                           "opfnamespace, "
5301                                           "(%s opfowner) AS rolname "
5302                                           "FROM pg_opfamily",
5303                                           username_subquery);
5304
5305         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5306
5307         ntups = PQntuples(res);
5308         *numOpfamilies = ntups;
5309
5310         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5311
5312         i_tableoid = PQfnumber(res, "tableoid");
5313         i_oid = PQfnumber(res, "oid");
5314         i_opfname = PQfnumber(res, "opfname");
5315         i_opfnamespace = PQfnumber(res, "opfnamespace");
5316         i_rolname = PQfnumber(res, "rolname");
5317
5318         for (i = 0; i < ntups; i++)
5319         {
5320                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5321                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5322                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5323                 AssignDumpId(&opfinfo[i].dobj);
5324                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5325                 opfinfo[i].dobj.namespace =
5326                         findNamespace(fout,
5327                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5328                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5329
5330                 /* Decide whether we want to dump it */
5331                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5332
5333                 /* Extensions do not currently have ACLs. */
5334                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5335
5336                 if (strlen(opfinfo[i].rolname) == 0)
5337                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5338                                           opfinfo[i].dobj.name);
5339         }
5340
5341         PQclear(res);
5342
5343         destroyPQExpBuffer(query);
5344
5345         return opfinfo;
5346 }
5347
5348 /*
5349  * getAggregates:
5350  *        read all the user-defined aggregates in the system catalogs and
5351  * return them in the AggInfo* structure
5352  *
5353  * numAggs is set to the number of aggregates read in
5354  */
5355 AggInfo *
5356 getAggregates(Archive *fout, int *numAggs)
5357 {
5358         DumpOptions *dopt = fout->dopt;
5359         PGresult   *res;
5360         int                     ntups;
5361         int                     i;
5362         PQExpBuffer query = createPQExpBuffer();
5363         AggInfo    *agginfo;
5364         int                     i_tableoid;
5365         int                     i_oid;
5366         int                     i_aggname;
5367         int                     i_aggnamespace;
5368         int                     i_pronargs;
5369         int                     i_proargtypes;
5370         int                     i_rolname;
5371         int                     i_aggacl;
5372         int                     i_raggacl;
5373         int                     i_initaggacl;
5374         int                     i_initraggacl;
5375
5376         /*
5377          * Find all interesting aggregates.  See comment in getFuncs() for the
5378          * rationale behind the filtering logic.
5379          */
5380         if (fout->remoteVersion >= 90600)
5381         {
5382                 PQExpBuffer acl_subquery = createPQExpBuffer();
5383                 PQExpBuffer racl_subquery = createPQExpBuffer();
5384                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5385                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5386                 const char *agg_check;
5387
5388                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5389                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5390                                                 dopt->binary_upgrade);
5391
5392                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5393                                          : "p.proisagg");
5394
5395                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5396                                                   "p.proname AS aggname, "
5397                                                   "p.pronamespace AS aggnamespace, "
5398                                                   "p.pronargs, p.proargtypes, "
5399                                                   "(%s p.proowner) AS rolname, "
5400                                                   "%s AS aggacl, "
5401                                                   "%s AS raggacl, "
5402                                                   "%s AS initaggacl, "
5403                                                   "%s AS initraggacl "
5404                                                   "FROM pg_proc p "
5405                                                   "LEFT JOIN pg_init_privs pip ON "
5406                                                   "(p.oid = pip.objoid "
5407                                                   "AND pip.classoid = 'pg_proc'::regclass "
5408                                                   "AND pip.objsubid = 0) "
5409                                                   "WHERE %s AND ("
5410                                                   "p.pronamespace != "
5411                                                   "(SELECT oid FROM pg_namespace "
5412                                                   "WHERE nspname = 'pg_catalog') OR "
5413                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5414                                                   username_subquery,
5415                                                   acl_subquery->data,
5416                                                   racl_subquery->data,
5417                                                   initacl_subquery->data,
5418                                                   initracl_subquery->data,
5419                                                   agg_check);
5420                 if (dopt->binary_upgrade)
5421                         appendPQExpBufferStr(query,
5422                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5423                                                                  "classid = 'pg_proc'::regclass AND "
5424                                                                  "objid = p.oid AND "
5425                                                                  "refclassid = 'pg_extension'::regclass AND "
5426                                                                  "deptype = 'e')");
5427                 appendPQExpBufferChar(query, ')');
5428
5429                 destroyPQExpBuffer(acl_subquery);
5430                 destroyPQExpBuffer(racl_subquery);
5431                 destroyPQExpBuffer(initacl_subquery);
5432                 destroyPQExpBuffer(initracl_subquery);
5433         }
5434         else if (fout->remoteVersion >= 80200)
5435         {
5436                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5437                                                   "pronamespace AS aggnamespace, "
5438                                                   "pronargs, proargtypes, "
5439                                                   "(%s proowner) AS rolname, "
5440                                                   "proacl AS aggacl, "
5441                                                   "NULL AS raggacl, "
5442                                                   "NULL AS initaggacl, NULL AS initraggacl "
5443                                                   "FROM pg_proc p "
5444                                                   "WHERE proisagg AND ("
5445                                                   "pronamespace != "
5446                                                   "(SELECT oid FROM pg_namespace "
5447                                                   "WHERE nspname = 'pg_catalog')",
5448                                                   username_subquery);
5449                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5450                         appendPQExpBufferStr(query,
5451                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5452                                                                  "classid = 'pg_proc'::regclass AND "
5453                                                                  "objid = p.oid AND "
5454                                                                  "refclassid = 'pg_extension'::regclass AND "
5455                                                                  "deptype = 'e')");
5456                 appendPQExpBufferChar(query, ')');
5457         }
5458         else
5459         {
5460                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5461                                                   "pronamespace AS aggnamespace, "
5462                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5463                                                   "proargtypes, "
5464                                                   "(%s proowner) AS rolname, "
5465                                                   "proacl AS aggacl, "
5466                                                   "NULL AS raggacl, "
5467                                                   "NULL AS initaggacl, NULL AS initraggacl "
5468                                                   "FROM pg_proc "
5469                                                   "WHERE proisagg "
5470                                                   "AND pronamespace != "
5471                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5472                                                   username_subquery);
5473         }
5474
5475         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5476
5477         ntups = PQntuples(res);
5478         *numAggs = ntups;
5479
5480         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5481
5482         i_tableoid = PQfnumber(res, "tableoid");
5483         i_oid = PQfnumber(res, "oid");
5484         i_aggname = PQfnumber(res, "aggname");
5485         i_aggnamespace = PQfnumber(res, "aggnamespace");
5486         i_pronargs = PQfnumber(res, "pronargs");
5487         i_proargtypes = PQfnumber(res, "proargtypes");
5488         i_rolname = PQfnumber(res, "rolname");
5489         i_aggacl = PQfnumber(res, "aggacl");
5490         i_raggacl = PQfnumber(res, "raggacl");
5491         i_initaggacl = PQfnumber(res, "initaggacl");
5492         i_initraggacl = PQfnumber(res, "initraggacl");
5493
5494         for (i = 0; i < ntups; i++)
5495         {
5496                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5497                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5498                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5499                 AssignDumpId(&agginfo[i].aggfn.dobj);
5500                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5501                 agginfo[i].aggfn.dobj.namespace =
5502                         findNamespace(fout,
5503                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5504                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5505                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5506                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5507                                           agginfo[i].aggfn.dobj.name);
5508                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5509                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5510                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5511                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5512                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5513                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5514                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5515                 if (agginfo[i].aggfn.nargs == 0)
5516                         agginfo[i].aggfn.argtypes = NULL;
5517                 else
5518                 {
5519                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5520                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5521                                                   agginfo[i].aggfn.argtypes,
5522                                                   agginfo[i].aggfn.nargs);
5523                 }
5524
5525                 /* Decide whether we want to dump it */
5526                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5527
5528                 /* Do not try to dump ACL if no ACL exists. */
5529                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5530                         PQgetisnull(res, i, i_initaggacl) &&
5531                         PQgetisnull(res, i, i_initraggacl))
5532                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5533         }
5534
5535         PQclear(res);
5536
5537         destroyPQExpBuffer(query);
5538
5539         return agginfo;
5540 }
5541
5542 /*
5543  * getFuncs:
5544  *        read all the user-defined functions in the system catalogs and
5545  * return them in the FuncInfo* structure
5546  *
5547  * numFuncs is set to the number of functions read in
5548  */
5549 FuncInfo *
5550 getFuncs(Archive *fout, int *numFuncs)
5551 {
5552         DumpOptions *dopt = fout->dopt;
5553         PGresult   *res;
5554         int                     ntups;
5555         int                     i;
5556         PQExpBuffer query = createPQExpBuffer();
5557         FuncInfo   *finfo;
5558         int                     i_tableoid;
5559         int                     i_oid;
5560         int                     i_proname;
5561         int                     i_pronamespace;
5562         int                     i_rolname;
5563         int                     i_prolang;
5564         int                     i_pronargs;
5565         int                     i_proargtypes;
5566         int                     i_prorettype;
5567         int                     i_proacl;
5568         int                     i_rproacl;
5569         int                     i_initproacl;
5570         int                     i_initrproacl;
5571
5572         /*
5573          * Find all interesting functions.  This is a bit complicated:
5574          *
5575          * 1. Always exclude aggregates; those are handled elsewhere.
5576          *
5577          * 2. Always exclude functions that are internally dependent on something
5578          * else, since presumably those will be created as a result of creating
5579          * the something else.  This currently acts only to suppress constructor
5580          * functions for range types (so we only need it in 9.2 and up).  Note
5581          * this is OK only because the constructors don't have any dependencies
5582          * the range type doesn't have; otherwise we might not get creation
5583          * ordering correct.
5584          *
5585          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5586          * they're members of extensions and we are in binary-upgrade mode then
5587          * include them, since we want to dump extension members individually in
5588          * that mode.  Also, if they are used by casts or transforms then we need
5589          * to gather the information about them, though they won't be dumped if
5590          * they are built-in.  Also, in 9.6 and up, include functions in
5591          * pg_catalog if they have an ACL different from what's shown in
5592          * pg_init_privs.
5593          */
5594         if (fout->remoteVersion >= 90600)
5595         {
5596                 PQExpBuffer acl_subquery = createPQExpBuffer();
5597                 PQExpBuffer racl_subquery = createPQExpBuffer();
5598                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5599                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5600                 const char *not_agg_check;
5601
5602                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5603                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5604                                                 dopt->binary_upgrade);
5605
5606                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5607                                                  : "NOT p.proisagg");
5608
5609                 appendPQExpBuffer(query,
5610                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5611                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5612                                                   "%s AS proacl, "
5613                                                   "%s AS rproacl, "
5614                                                   "%s AS initproacl, "
5615                                                   "%s AS initrproacl, "
5616                                                   "p.pronamespace, "
5617                                                   "(%s p.proowner) AS rolname "
5618                                                   "FROM pg_proc p "
5619                                                   "LEFT JOIN pg_init_privs pip ON "
5620                                                   "(p.oid = pip.objoid "
5621                                                   "AND pip.classoid = 'pg_proc'::regclass "
5622                                                   "AND pip.objsubid = 0) "
5623                                                   "WHERE %s"
5624                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5625                                                   "WHERE classid = 'pg_proc'::regclass AND "
5626                                                   "objid = p.oid AND deptype = 'i')"
5627                                                   "\n  AND ("
5628                                                   "\n  pronamespace != "
5629                                                   "(SELECT oid FROM pg_namespace "
5630                                                   "WHERE nspname = 'pg_catalog')"
5631                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5632                                                   "\n  WHERE pg_cast.oid > %u "
5633                                                   "\n  AND p.oid = pg_cast.castfunc)"
5634                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5635                                                   "\n  WHERE pg_transform.oid > %u AND "
5636                                                   "\n  (p.oid = pg_transform.trffromsql"
5637                                                   "\n  OR p.oid = pg_transform.trftosql))",
5638                                                   acl_subquery->data,
5639                                                   racl_subquery->data,
5640                                                   initacl_subquery->data,
5641                                                   initracl_subquery->data,
5642                                                   username_subquery,
5643                                                   not_agg_check,
5644                                                   g_last_builtin_oid,
5645                                                   g_last_builtin_oid);
5646                 if (dopt->binary_upgrade)
5647                         appendPQExpBufferStr(query,
5648                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5649                                                                  "classid = 'pg_proc'::regclass AND "
5650                                                                  "objid = p.oid AND "
5651                                                                  "refclassid = 'pg_extension'::regclass AND "
5652                                                                  "deptype = 'e')");
5653                 appendPQExpBufferStr(query,
5654                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5655                 appendPQExpBufferChar(query, ')');
5656
5657                 destroyPQExpBuffer(acl_subquery);
5658                 destroyPQExpBuffer(racl_subquery);
5659                 destroyPQExpBuffer(initacl_subquery);
5660                 destroyPQExpBuffer(initracl_subquery);
5661         }
5662         else
5663         {
5664                 appendPQExpBuffer(query,
5665                                                   "SELECT tableoid, oid, proname, prolang, "
5666                                                   "pronargs, proargtypes, prorettype, proacl, "
5667                                                   "NULL as rproacl, "
5668                                                   "NULL as initproacl, NULL AS initrproacl, "
5669                                                   "pronamespace, "
5670                                                   "(%s proowner) AS rolname "
5671                                                   "FROM pg_proc p "
5672                                                   "WHERE NOT proisagg",
5673                                                   username_subquery);
5674                 if (fout->remoteVersion >= 90200)
5675                         appendPQExpBufferStr(query,
5676                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5677                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5678                                                                  "objid = p.oid AND deptype = 'i')");
5679                 appendPQExpBuffer(query,
5680                                                   "\n  AND ("
5681                                                   "\n  pronamespace != "
5682                                                   "(SELECT oid FROM pg_namespace "
5683                                                   "WHERE nspname = 'pg_catalog')"
5684                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5685                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5686                                                   "\n  AND p.oid = pg_cast.castfunc)",
5687                                                   g_last_builtin_oid);
5688
5689                 if (fout->remoteVersion >= 90500)
5690                         appendPQExpBuffer(query,
5691                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5692                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5693                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5694                                                           "\n  OR p.oid = pg_transform.trftosql))",
5695                                                           g_last_builtin_oid);
5696
5697                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5698                         appendPQExpBufferStr(query,
5699                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5700                                                                  "classid = 'pg_proc'::regclass AND "
5701                                                                  "objid = p.oid AND "
5702                                                                  "refclassid = 'pg_extension'::regclass AND "
5703                                                                  "deptype = 'e')");
5704                 appendPQExpBufferChar(query, ')');
5705         }
5706
5707         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5708
5709         ntups = PQntuples(res);
5710
5711         *numFuncs = ntups;
5712
5713         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5714
5715         i_tableoid = PQfnumber(res, "tableoid");
5716         i_oid = PQfnumber(res, "oid");
5717         i_proname = PQfnumber(res, "proname");
5718         i_pronamespace = PQfnumber(res, "pronamespace");
5719         i_rolname = PQfnumber(res, "rolname");
5720         i_prolang = PQfnumber(res, "prolang");
5721         i_pronargs = PQfnumber(res, "pronargs");
5722         i_proargtypes = PQfnumber(res, "proargtypes");
5723         i_prorettype = PQfnumber(res, "prorettype");
5724         i_proacl = PQfnumber(res, "proacl");
5725         i_rproacl = PQfnumber(res, "rproacl");
5726         i_initproacl = PQfnumber(res, "initproacl");
5727         i_initrproacl = PQfnumber(res, "initrproacl");
5728
5729         for (i = 0; i < ntups; i++)
5730         {
5731                 finfo[i].dobj.objType = DO_FUNC;
5732                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5733                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5734                 AssignDumpId(&finfo[i].dobj);
5735                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5736                 finfo[i].dobj.namespace =
5737                         findNamespace(fout,
5738                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5739                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5740                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5741                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5742                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5743                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5744                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5745                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5746                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5747                 if (finfo[i].nargs == 0)
5748                         finfo[i].argtypes = NULL;
5749                 else
5750                 {
5751                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5752                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5753                                                   finfo[i].argtypes, finfo[i].nargs);
5754                 }
5755
5756                 /* Decide whether we want to dump it */
5757                 selectDumpableObject(&(finfo[i].dobj), fout);
5758
5759                 /* Do not try to dump ACL if no ACL exists. */
5760                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5761                         PQgetisnull(res, i, i_initproacl) &&
5762                         PQgetisnull(res, i, i_initrproacl))
5763                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5764
5765                 if (strlen(finfo[i].rolname) == 0)
5766                         write_msg(NULL,
5767                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5768                                           finfo[i].dobj.name);
5769         }
5770
5771         PQclear(res);
5772
5773         destroyPQExpBuffer(query);
5774
5775         return finfo;
5776 }
5777
5778 /*
5779  * getTables
5780  *        read all the tables (no indexes)
5781  * in the system catalogs return them in the TableInfo* structure
5782  *
5783  * numTables is set to the number of tables read in
5784  */
5785 TableInfo *
5786 getTables(Archive *fout, int *numTables)
5787 {
5788         DumpOptions *dopt = fout->dopt;
5789         PGresult   *res;
5790         int                     ntups;
5791         int                     i;
5792         PQExpBuffer query = createPQExpBuffer();
5793         TableInfo  *tblinfo;
5794         int                     i_reltableoid;
5795         int                     i_reloid;
5796         int                     i_relname;
5797         int                     i_relnamespace;
5798         int                     i_relkind;
5799         int                     i_relacl;
5800         int                     i_rrelacl;
5801         int                     i_initrelacl;
5802         int                     i_initrrelacl;
5803         int                     i_rolname;
5804         int                     i_relchecks;
5805         int                     i_relhastriggers;
5806         int                     i_relhasindex;
5807         int                     i_relhasrules;
5808         int                     i_relrowsec;
5809         int                     i_relforcerowsec;
5810         int                     i_relhasoids;
5811         int                     i_relfrozenxid;
5812         int                     i_relminmxid;
5813         int                     i_toastoid;
5814         int                     i_toastfrozenxid;
5815         int                     i_toastminmxid;
5816         int                     i_relpersistence;
5817         int                     i_relispopulated;
5818         int                     i_relreplident;
5819         int                     i_owning_tab;
5820         int                     i_owning_col;
5821         int                     i_reltablespace;
5822         int                     i_reloptions;
5823         int                     i_checkoption;
5824         int                     i_toastreloptions;
5825         int                     i_reloftype;
5826         int                     i_relpages;
5827         int                     i_is_identity_sequence;
5828         int                     i_changed_acl;
5829         int                     i_partkeydef;
5830         int                     i_ispartition;
5831         int                     i_partbound;
5832
5833         /*
5834          * Find all the tables and table-like objects.
5835          *
5836          * We include system catalogs, so that we can work if a user table is
5837          * defined to inherit from a system catalog (pretty weird, but...)
5838          *
5839          * We ignore relations that are not ordinary tables, sequences, views,
5840          * materialized views, composite types, or foreign tables.
5841          *
5842          * Composite-type table entries won't be dumped as such, but we have to
5843          * make a DumpableObject for them so that we can track dependencies of the
5844          * composite type (pg_depend entries for columns of the composite type
5845          * link to the pg_class entry not the pg_type entry).
5846          *
5847          * Note: in this phase we should collect only a minimal amount of
5848          * information about each table, basically just enough to decide if it is
5849          * interesting. We must fetch all tables in this phase because otherwise
5850          * we cannot correctly identify inherited columns, owned sequences, etc.
5851          */
5852
5853         if (fout->remoteVersion >= 90600)
5854         {
5855                 char       *partkeydef = "NULL";
5856                 char       *ispartition = "false";
5857                 char       *partbound = "NULL";
5858                 char       *relhasoids = "c.relhasoids";
5859
5860                 PQExpBuffer acl_subquery = createPQExpBuffer();
5861                 PQExpBuffer racl_subquery = createPQExpBuffer();
5862                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5863                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5864
5865                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5866                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5867                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5868                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5869
5870                 /*
5871                  * Collect the information about any partitioned tables, which were
5872                  * added in PG10.
5873                  */
5874
5875                 if (fout->remoteVersion >= 100000)
5876                 {
5877                         partkeydef = "pg_get_partkeydef(c.oid)";
5878                         ispartition = "c.relispartition";
5879                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5880                 }
5881
5882                 /* In PG12 upwards WITH OIDS does not exist anymore. */
5883                 if (fout->remoteVersion >= 120000)
5884                         relhasoids = "'f'::bool";
5885
5886                 /*
5887                  * Left join to pick up dependency info linking sequences to their
5888                  * owning column, if any (note this dependency is AUTO as of 8.2)
5889                  *
5890                  * Left join to detect if any privileges are still as-set-at-init, in
5891                  * which case we won't dump out ACL commands for those.
5892                  */
5893
5894                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5895                                                 initracl_subquery, "c.relacl", "c.relowner",
5896                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5897                                                 " THEN 's' ELSE 'r' END::\"char\"",
5898                                                 dopt->binary_upgrade);
5899
5900                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5901                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5902                                                 dopt->binary_upgrade);
5903
5904                 appendPQExpBuffer(query,
5905                                                   "SELECT c.tableoid, c.oid, c.relname, "
5906                                                   "%s AS relacl, %s as rrelacl, "
5907                                                   "%s AS initrelacl, %s as initrrelacl, "
5908                                                   "c.relkind, c.relnamespace, "
5909                                                   "(%s c.relowner) AS rolname, "
5910                                                   "c.relchecks, c.relhastriggers, "
5911                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
5912                                                   "c.relrowsecurity, c.relforcerowsecurity, "
5913                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5914                                                   "tc.relfrozenxid AS tfrozenxid, "
5915                                                   "tc.relminmxid AS tminmxid, "
5916                                                   "c.relpersistence, c.relispopulated, "
5917                                                   "c.relreplident, c.relpages, "
5918                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5919                                                   "d.refobjid AS owning_tab, "
5920                                                   "d.refobjsubid AS owning_col, "
5921                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5922                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5923                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5924                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5925                                                   "tc.reloptions AS toast_reloptions, "
5926                                                   "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, "
5927                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5928                                                   "(c.oid = pip.objoid "
5929                                                   "AND pip.classoid = 'pg_class'::regclass "
5930                                                   "AND pip.objsubid = at.attnum)"
5931                                                   "WHERE at.attrelid = c.oid AND ("
5932                                                   "%s IS NOT NULL "
5933                                                   "OR %s IS NOT NULL "
5934                                                   "OR %s IS NOT NULL "
5935                                                   "OR %s IS NOT NULL"
5936                                                   "))"
5937                                                   "AS changed_acl, "
5938                                                   "%s AS partkeydef, "
5939                                                   "%s AS ispartition, "
5940                                                   "%s AS partbound "
5941                                                   "FROM pg_class c "
5942                                                   "LEFT JOIN pg_depend d ON "
5943                                                   "(c.relkind = '%c' AND "
5944                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
5945                                                   "d.objsubid = 0 AND "
5946                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
5947                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5948                                                   "LEFT JOIN pg_init_privs pip ON "
5949                                                   "(c.oid = pip.objoid "
5950                                                   "AND pip.classoid = 'pg_class'::regclass "
5951                                                   "AND pip.objsubid = 0) "
5952                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
5953                                                   "ORDER BY c.oid",
5954                                                   acl_subquery->data,
5955                                                   racl_subquery->data,
5956                                                   initacl_subquery->data,
5957                                                   initracl_subquery->data,
5958                                                   username_subquery,
5959                                                   relhasoids,
5960                                                   RELKIND_SEQUENCE,
5961                                                   attacl_subquery->data,
5962                                                   attracl_subquery->data,
5963                                                   attinitacl_subquery->data,
5964                                                   attinitracl_subquery->data,
5965                                                   partkeydef,
5966                                                   ispartition,
5967                                                   partbound,
5968                                                   RELKIND_SEQUENCE,
5969                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
5970                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5971                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
5972                                                   RELKIND_PARTITIONED_TABLE);
5973
5974                 destroyPQExpBuffer(acl_subquery);
5975                 destroyPQExpBuffer(racl_subquery);
5976                 destroyPQExpBuffer(initacl_subquery);
5977                 destroyPQExpBuffer(initracl_subquery);
5978
5979                 destroyPQExpBuffer(attacl_subquery);
5980                 destroyPQExpBuffer(attracl_subquery);
5981                 destroyPQExpBuffer(attinitacl_subquery);
5982                 destroyPQExpBuffer(attinitracl_subquery);
5983         }
5984         else if (fout->remoteVersion >= 90500)
5985         {
5986                 /*
5987                  * Left join to pick up dependency info linking sequences to their
5988                  * owning column, if any (note this dependency is AUTO as of 8.2)
5989                  */
5990                 appendPQExpBuffer(query,
5991                                                   "SELECT c.tableoid, c.oid, c.relname, "
5992                                                   "c.relacl, NULL as rrelacl, "
5993                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
5994                                                   "c.relkind, "
5995                                                   "c.relnamespace, "
5996                                                   "(%s c.relowner) AS rolname, "
5997                                                   "c.relchecks, c.relhastriggers, "
5998                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
5999                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6000                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6001                                                   "tc.relfrozenxid AS tfrozenxid, "
6002                                                   "tc.relminmxid AS tminmxid, "
6003                                                   "c.relpersistence, c.relispopulated, "
6004                                                   "c.relreplident, c.relpages, "
6005                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6006                                                   "d.refobjid AS owning_tab, "
6007                                                   "d.refobjsubid AS owning_col, "
6008                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6009                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6010                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6011                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6012                                                   "tc.reloptions AS toast_reloptions, "
6013                                                   "NULL AS changed_acl, "
6014                                                   "NULL AS partkeydef, "
6015                                                   "false AS ispartition, "
6016                                                   "NULL AS partbound "
6017                                                   "FROM pg_class c "
6018                                                   "LEFT JOIN pg_depend d ON "
6019                                                   "(c.relkind = '%c' AND "
6020                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6021                                                   "d.objsubid = 0 AND "
6022                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6023                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6024                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6025                                                   "ORDER BY c.oid",
6026                                                   username_subquery,
6027                                                   RELKIND_SEQUENCE,
6028                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6029                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6030                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6031         }
6032         else if (fout->remoteVersion >= 90400)
6033         {
6034                 /*
6035                  * Left join to pick up dependency info linking sequences to their
6036                  * owning column, if any (note this dependency is AUTO as of 8.2)
6037                  */
6038                 appendPQExpBuffer(query,
6039                                                   "SELECT c.tableoid, c.oid, c.relname, "
6040                                                   "c.relacl, NULL as rrelacl, "
6041                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6042                                                   "c.relkind, "
6043                                                   "c.relnamespace, "
6044                                                   "(%s c.relowner) AS rolname, "
6045                                                   "c.relchecks, c.relhastriggers, "
6046                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6047                                                   "'f'::bool AS relrowsecurity, "
6048                                                   "'f'::bool AS relforcerowsecurity, "
6049                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6050                                                   "tc.relfrozenxid AS tfrozenxid, "
6051                                                   "tc.relminmxid AS tminmxid, "
6052                                                   "c.relpersistence, c.relispopulated, "
6053                                                   "c.relreplident, c.relpages, "
6054                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6055                                                   "d.refobjid AS owning_tab, "
6056                                                   "d.refobjsubid AS owning_col, "
6057                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6058                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6059                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6060                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6061                                                   "tc.reloptions AS toast_reloptions, "
6062                                                   "NULL AS changed_acl, "
6063                                                   "NULL AS partkeydef, "
6064                                                   "false AS ispartition, "
6065                                                   "NULL AS partbound "
6066                                                   "FROM pg_class c "
6067                                                   "LEFT JOIN pg_depend d ON "
6068                                                   "(c.relkind = '%c' AND "
6069                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6070                                                   "d.objsubid = 0 AND "
6071                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6072                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6073                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6074                                                   "ORDER BY c.oid",
6075                                                   username_subquery,
6076                                                   RELKIND_SEQUENCE,
6077                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6078                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6079                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6080         }
6081         else if (fout->remoteVersion >= 90300)
6082         {
6083                 /*
6084                  * Left join to pick up dependency info linking sequences to their
6085                  * owning column, if any (note this dependency is AUTO as of 8.2)
6086                  */
6087                 appendPQExpBuffer(query,
6088                                                   "SELECT c.tableoid, c.oid, c.relname, "
6089                                                   "c.relacl, NULL as rrelacl, "
6090                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6091                                                   "c.relkind, "
6092                                                   "c.relnamespace, "
6093                                                   "(%s c.relowner) AS rolname, "
6094                                                   "c.relchecks, c.relhastriggers, "
6095                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6096                                                   "'f'::bool AS relrowsecurity, "
6097                                                   "'f'::bool AS relforcerowsecurity, "
6098                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6099                                                   "tc.relfrozenxid AS tfrozenxid, "
6100                                                   "tc.relminmxid AS tminmxid, "
6101                                                   "c.relpersistence, c.relispopulated, "
6102                                                   "'d' AS relreplident, c.relpages, "
6103                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6104                                                   "d.refobjid AS owning_tab, "
6105                                                   "d.refobjsubid AS owning_col, "
6106                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6107                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6108                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6109                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6110                                                   "tc.reloptions AS toast_reloptions, "
6111                                                   "NULL AS changed_acl, "
6112                                                   "NULL AS partkeydef, "
6113                                                   "false AS ispartition, "
6114                                                   "NULL AS partbound "
6115                                                   "FROM pg_class c "
6116                                                   "LEFT JOIN pg_depend d ON "
6117                                                   "(c.relkind = '%c' AND "
6118                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6119                                                   "d.objsubid = 0 AND "
6120                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6121                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6122                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6123                                                   "ORDER BY c.oid",
6124                                                   username_subquery,
6125                                                   RELKIND_SEQUENCE,
6126                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6127                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6128                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6129         }
6130         else if (fout->remoteVersion >= 90100)
6131         {
6132                 /*
6133                  * Left join to pick up dependency info linking sequences to their
6134                  * owning column, if any (note this dependency is AUTO as of 8.2)
6135                  */
6136                 appendPQExpBuffer(query,
6137                                                   "SELECT c.tableoid, c.oid, c.relname, "
6138                                                   "c.relacl, NULL as rrelacl, "
6139                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6140                                                   "c.relkind, "
6141                                                   "c.relnamespace, "
6142                                                   "(%s c.relowner) AS rolname, "
6143                                                   "c.relchecks, c.relhastriggers, "
6144                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6145                                                   "'f'::bool AS relrowsecurity, "
6146                                                   "'f'::bool AS relforcerowsecurity, "
6147                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6148                                                   "tc.relfrozenxid AS tfrozenxid, "
6149                                                   "0 AS tminmxid, "
6150                                                   "c.relpersistence, 't' as relispopulated, "
6151                                                   "'d' AS relreplident, c.relpages, "
6152                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6153                                                   "d.refobjid AS owning_tab, "
6154                                                   "d.refobjsubid AS owning_col, "
6155                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6156                                                   "c.reloptions AS reloptions, "
6157                                                   "tc.reloptions AS toast_reloptions, "
6158                                                   "NULL AS changed_acl, "
6159                                                   "NULL AS partkeydef, "
6160                                                   "false AS ispartition, "
6161                                                   "NULL AS partbound "
6162                                                   "FROM pg_class c "
6163                                                   "LEFT JOIN pg_depend d ON "
6164                                                   "(c.relkind = '%c' AND "
6165                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6166                                                   "d.objsubid = 0 AND "
6167                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6168                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6169                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6170                                                   "ORDER BY c.oid",
6171                                                   username_subquery,
6172                                                   RELKIND_SEQUENCE,
6173                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6174                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6175                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6176         }
6177         else if (fout->remoteVersion >= 90000)
6178         {
6179                 /*
6180                  * Left join to pick up dependency info linking sequences to their
6181                  * owning column, if any (note this dependency is AUTO as of 8.2)
6182                  */
6183                 appendPQExpBuffer(query,
6184                                                   "SELECT c.tableoid, c.oid, c.relname, "
6185                                                   "c.relacl, NULL as rrelacl, "
6186                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6187                                                   "c.relkind, "
6188                                                   "c.relnamespace, "
6189                                                   "(%s c.relowner) AS rolname, "
6190                                                   "c.relchecks, c.relhastriggers, "
6191                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6192                                                   "'f'::bool AS relrowsecurity, "
6193                                                   "'f'::bool AS relforcerowsecurity, "
6194                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6195                                                   "tc.relfrozenxid AS tfrozenxid, "
6196                                                   "0 AS tminmxid, "
6197                                                   "'p' AS relpersistence, 't' as relispopulated, "
6198                                                   "'d' AS relreplident, c.relpages, "
6199                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6200                                                   "d.refobjid AS owning_tab, "
6201                                                   "d.refobjsubid AS owning_col, "
6202                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6203                                                   "c.reloptions AS reloptions, "
6204                                                   "tc.reloptions AS toast_reloptions, "
6205                                                   "NULL AS changed_acl, "
6206                                                   "NULL AS partkeydef, "
6207                                                   "false AS ispartition, "
6208                                                   "NULL AS partbound "
6209                                                   "FROM pg_class c "
6210                                                   "LEFT JOIN pg_depend d ON "
6211                                                   "(c.relkind = '%c' AND "
6212                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6213                                                   "d.objsubid = 0 AND "
6214                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6215                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6216                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6217                                                   "ORDER BY c.oid",
6218                                                   username_subquery,
6219                                                   RELKIND_SEQUENCE,
6220                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6221                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6222         }
6223         else if (fout->remoteVersion >= 80400)
6224         {
6225                 /*
6226                  * Left join to pick up dependency info linking sequences to their
6227                  * owning column, if any (note this dependency is AUTO as of 8.2)
6228                  */
6229                 appendPQExpBuffer(query,
6230                                                   "SELECT c.tableoid, c.oid, c.relname, "
6231                                                   "c.relacl, NULL as rrelacl, "
6232                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6233                                                   "c.relkind, "
6234                                                   "c.relnamespace, "
6235                                                   "(%s c.relowner) AS rolname, "
6236                                                   "c.relchecks, c.relhastriggers, "
6237                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6238                                                   "'f'::bool AS relrowsecurity, "
6239                                                   "'f'::bool AS relforcerowsecurity, "
6240                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6241                                                   "tc.relfrozenxid AS tfrozenxid, "
6242                                                   "0 AS tminmxid, "
6243                                                   "'p' AS relpersistence, 't' as relispopulated, "
6244                                                   "'d' AS relreplident, c.relpages, "
6245                                                   "NULL AS reloftype, "
6246                                                   "d.refobjid AS owning_tab, "
6247                                                   "d.refobjsubid AS owning_col, "
6248                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6249                                                   "c.reloptions AS reloptions, "
6250                                                   "tc.reloptions AS toast_reloptions, "
6251                                                   "NULL AS changed_acl, "
6252                                                   "NULL AS partkeydef, "
6253                                                   "false AS ispartition, "
6254                                                   "NULL AS partbound "
6255                                                   "FROM pg_class c "
6256                                                   "LEFT JOIN pg_depend d ON "
6257                                                   "(c.relkind = '%c' AND "
6258                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6259                                                   "d.objsubid = 0 AND "
6260                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6261                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6262                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6263                                                   "ORDER BY c.oid",
6264                                                   username_subquery,
6265                                                   RELKIND_SEQUENCE,
6266                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6267                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6268         }
6269         else if (fout->remoteVersion >= 80200)
6270         {
6271                 /*
6272                  * Left join to pick up dependency info linking sequences to their
6273                  * owning column, if any (note this dependency is AUTO as of 8.2)
6274                  */
6275                 appendPQExpBuffer(query,
6276                                                   "SELECT c.tableoid, c.oid, c.relname, "
6277                                                   "c.relacl, NULL as rrelacl, "
6278                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6279                                                   "c.relkind, "
6280                                                   "c.relnamespace, "
6281                                                   "(%s c.relowner) AS rolname, "
6282                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6283                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6284                                                   "'f'::bool AS relrowsecurity, "
6285                                                   "'f'::bool AS relforcerowsecurity, "
6286                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6287                                                   "tc.relfrozenxid AS tfrozenxid, "
6288                                                   "0 AS tminmxid, "
6289                                                   "'p' AS relpersistence, 't' as relispopulated, "
6290                                                   "'d' AS relreplident, c.relpages, "
6291                                                   "NULL AS reloftype, "
6292                                                   "d.refobjid AS owning_tab, "
6293                                                   "d.refobjsubid AS owning_col, "
6294                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6295                                                   "c.reloptions AS reloptions, "
6296                                                   "NULL AS toast_reloptions, "
6297                                                   "NULL AS changed_acl, "
6298                                                   "NULL AS partkeydef, "
6299                                                   "false AS ispartition, "
6300                                                   "NULL AS partbound "
6301                                                   "FROM pg_class c "
6302                                                   "LEFT JOIN pg_depend d ON "
6303                                                   "(c.relkind = '%c' AND "
6304                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6305                                                   "d.objsubid = 0 AND "
6306                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6307                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6308                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6309                                                   "ORDER BY c.oid",
6310                                                   username_subquery,
6311                                                   RELKIND_SEQUENCE,
6312                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6313                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6314         }
6315         else
6316         {
6317                 /*
6318                  * Left join to pick up dependency info linking sequences to their
6319                  * owning column, if any
6320                  */
6321                 appendPQExpBuffer(query,
6322                                                   "SELECT c.tableoid, c.oid, relname, "
6323                                                   "relacl, NULL as rrelacl, "
6324                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6325                                                   "relkind, relnamespace, "
6326                                                   "(%s relowner) AS rolname, "
6327                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6328                                                   "relhasindex, relhasrules, relhasoids, "
6329                                                   "'f'::bool AS relrowsecurity, "
6330                                                   "'f'::bool AS relforcerowsecurity, "
6331                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6332                                                   "0 AS toid, "
6333                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6334                                                   "'p' AS relpersistence, 't' as relispopulated, "
6335                                                   "'d' AS relreplident, relpages, "
6336                                                   "NULL AS reloftype, "
6337                                                   "d.refobjid AS owning_tab, "
6338                                                   "d.refobjsubid AS owning_col, "
6339                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6340                                                   "NULL AS reloptions, "
6341                                                   "NULL AS toast_reloptions, "
6342                                                   "NULL AS changed_acl, "
6343                                                   "NULL AS partkeydef, "
6344                                                   "false AS ispartition, "
6345                                                   "NULL AS partbound "
6346                                                   "FROM pg_class c "
6347                                                   "LEFT JOIN pg_depend d ON "
6348                                                   "(c.relkind = '%c' AND "
6349                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6350                                                   "d.objsubid = 0 AND "
6351                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6352                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6353                                                   "ORDER BY c.oid",
6354                                                   username_subquery,
6355                                                   RELKIND_SEQUENCE,
6356                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6357                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6358         }
6359
6360         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6361
6362         ntups = PQntuples(res);
6363
6364         *numTables = ntups;
6365
6366         /*
6367          * Extract data from result and lock dumpable tables.  We do the locking
6368          * before anything else, to minimize the window wherein a table could
6369          * disappear under us.
6370          *
6371          * Note that we have to save info about all tables here, even when dumping
6372          * only one, because we don't yet know which tables might be inheritance
6373          * ancestors of the target table.
6374          */
6375         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6376
6377         i_reltableoid = PQfnumber(res, "tableoid");
6378         i_reloid = PQfnumber(res, "oid");
6379         i_relname = PQfnumber(res, "relname");
6380         i_relnamespace = PQfnumber(res, "relnamespace");
6381         i_relacl = PQfnumber(res, "relacl");
6382         i_rrelacl = PQfnumber(res, "rrelacl");
6383         i_initrelacl = PQfnumber(res, "initrelacl");
6384         i_initrrelacl = PQfnumber(res, "initrrelacl");
6385         i_relkind = PQfnumber(res, "relkind");
6386         i_rolname = PQfnumber(res, "rolname");
6387         i_relchecks = PQfnumber(res, "relchecks");
6388         i_relhastriggers = PQfnumber(res, "relhastriggers");
6389         i_relhasindex = PQfnumber(res, "relhasindex");
6390         i_relhasrules = PQfnumber(res, "relhasrules");
6391         i_relrowsec = PQfnumber(res, "relrowsecurity");
6392         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6393         i_relhasoids = PQfnumber(res, "relhasoids");
6394         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6395         i_relminmxid = PQfnumber(res, "relminmxid");
6396         i_toastoid = PQfnumber(res, "toid");
6397         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6398         i_toastminmxid = PQfnumber(res, "tminmxid");
6399         i_relpersistence = PQfnumber(res, "relpersistence");
6400         i_relispopulated = PQfnumber(res, "relispopulated");
6401         i_relreplident = PQfnumber(res, "relreplident");
6402         i_relpages = PQfnumber(res, "relpages");
6403         i_owning_tab = PQfnumber(res, "owning_tab");
6404         i_owning_col = PQfnumber(res, "owning_col");
6405         i_reltablespace = PQfnumber(res, "reltablespace");
6406         i_reloptions = PQfnumber(res, "reloptions");
6407         i_checkoption = PQfnumber(res, "checkoption");
6408         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6409         i_reloftype = PQfnumber(res, "reloftype");
6410         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6411         i_changed_acl = PQfnumber(res, "changed_acl");
6412         i_partkeydef = PQfnumber(res, "partkeydef");
6413         i_ispartition = PQfnumber(res, "ispartition");
6414         i_partbound = PQfnumber(res, "partbound");
6415
6416         if (dopt->lockWaitTimeout)
6417         {
6418                 /*
6419                  * Arrange to fail instead of waiting forever for a table lock.
6420                  *
6421                  * NB: this coding assumes that the only queries issued within the
6422                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6423                  * applied to other things too.
6424                  */
6425                 resetPQExpBuffer(query);
6426                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6427                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6428                 ExecuteSqlStatement(fout, query->data);
6429         }
6430
6431         for (i = 0; i < ntups; i++)
6432         {
6433                 tblinfo[i].dobj.objType = DO_TABLE;
6434                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6435                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6436                 AssignDumpId(&tblinfo[i].dobj);
6437                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6438                 tblinfo[i].dobj.namespace =
6439                         findNamespace(fout,
6440                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6441                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6442                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6443                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6444                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6445                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6446                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6447                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6448                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6449                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6450                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6451                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6452                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6453                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6454                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6455                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6456                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6457                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6458                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6459                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6460                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6461                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6462                 if (PQgetisnull(res, i, i_reloftype))
6463                         tblinfo[i].reloftype = NULL;
6464                 else
6465                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6466                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6467                 if (PQgetisnull(res, i, i_owning_tab))
6468                 {
6469                         tblinfo[i].owning_tab = InvalidOid;
6470                         tblinfo[i].owning_col = 0;
6471                 }
6472                 else
6473                 {
6474                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6475                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6476                 }
6477                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6478                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6479                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6480                         tblinfo[i].checkoption = NULL;
6481                 else
6482                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6483                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6484
6485                 /* other fields were zeroed above */
6486
6487                 /*
6488                  * Decide whether we want to dump this table.
6489                  */
6490                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6491                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6492                 else
6493                         selectDumpableTable(&tblinfo[i], fout);
6494
6495                 /*
6496                  * If the table-level and all column-level ACLs for this table are
6497                  * unchanged, then we don't need to worry about including the ACLs for
6498                  * this table.  If any column-level ACLs have been changed, the
6499                  * 'changed_acl' column from the query will indicate that.
6500                  *
6501                  * This can result in a significant performance improvement in cases
6502                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6503                  */
6504                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6505                         PQgetisnull(res, i, i_initrelacl) &&
6506                         PQgetisnull(res, i, i_initrrelacl) &&
6507                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6508                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6509
6510                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6511                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6512                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6513
6514                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6515                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6516
6517                 /* Partition key string or NULL */
6518                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6519                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6520                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6521
6522                 /*
6523                  * Read-lock target tables to make sure they aren't DROPPED or altered
6524                  * in schema before we get around to dumping them.
6525                  *
6526                  * Note that we don't explicitly lock parents of the target tables; we
6527                  * assume our lock on the child is enough to prevent schema
6528                  * alterations to parent tables.
6529                  *
6530                  * NOTE: it'd be kinda nice to lock other relations too, not only
6531                  * plain or partitioned tables, but the backend doesn't presently
6532                  * allow that.
6533                  *
6534                  * We only need to lock the table for certain components; see
6535                  * pg_dump.h
6536                  */
6537                 if (tblinfo[i].dobj.dump &&
6538                         (tblinfo[i].relkind == RELKIND_RELATION ||
6539                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6540                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6541                 {
6542                         resetPQExpBuffer(query);
6543                         appendPQExpBuffer(query,
6544                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6545                                                           fmtQualifiedDumpable(&tblinfo[i]));
6546                         ExecuteSqlStatement(fout, query->data);
6547                 }
6548
6549                 /* Emit notice if join for owner failed */
6550                 if (strlen(tblinfo[i].rolname) == 0)
6551                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6552                                           tblinfo[i].dobj.name);
6553         }
6554
6555         if (dopt->lockWaitTimeout)
6556         {
6557                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6558         }
6559
6560         PQclear(res);
6561
6562         destroyPQExpBuffer(query);
6563
6564         return tblinfo;
6565 }
6566
6567 /*
6568  * getOwnedSeqs
6569  *        identify owned sequences and mark them as dumpable if owning table is
6570  *
6571  * We used to do this in getTables(), but it's better to do it after the
6572  * index used by findTableByOid() has been set up.
6573  */
6574 void
6575 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6576 {
6577         int                     i;
6578
6579         /*
6580          * Force sequences that are "owned" by table columns to be dumped whenever
6581          * their owning table is being dumped.
6582          */
6583         for (i = 0; i < numTables; i++)
6584         {
6585                 TableInfo  *seqinfo = &tblinfo[i];
6586                 TableInfo  *owning_tab;
6587
6588                 if (!OidIsValid(seqinfo->owning_tab))
6589                         continue;                       /* not an owned sequence */
6590
6591                 owning_tab = findTableByOid(seqinfo->owning_tab);
6592                 if (owning_tab == NULL)
6593                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6594                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6595
6596                 /*
6597                  * Only dump identity sequences if we're going to dump the table that
6598                  * it belongs to.
6599                  */
6600                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6601                         seqinfo->is_identity_sequence)
6602                 {
6603                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6604                         continue;
6605                 }
6606
6607                 /*
6608                  * Otherwise we need to dump the components that are being dumped for
6609                  * the table and any components which the sequence is explicitly
6610                  * marked with.
6611                  *
6612                  * We can't simply use the set of components which are being dumped
6613                  * for the table as the table might be in an extension (and only the
6614                  * non-extension components, eg: ACLs if changed, security labels, and
6615                  * policies, are being dumped) while the sequence is not (and
6616                  * therefore the definition and other components should also be
6617                  * dumped).
6618                  *
6619                  * If the sequence is part of the extension then it should be properly
6620                  * marked by checkExtensionMembership() and this will be a no-op as
6621                  * the table will be equivalently marked.
6622                  */
6623                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6624
6625                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6626                         seqinfo->interesting = true;
6627         }
6628 }
6629
6630 /*
6631  * getInherits
6632  *        read all the inheritance information
6633  * from the system catalogs return them in the InhInfo* structure
6634  *
6635  * numInherits is set to the number of pairs read in
6636  */
6637 InhInfo *
6638 getInherits(Archive *fout, int *numInherits)
6639 {
6640         PGresult   *res;
6641         int                     ntups;
6642         int                     i;
6643         PQExpBuffer query = createPQExpBuffer();
6644         InhInfo    *inhinfo;
6645
6646         int                     i_inhrelid;
6647         int                     i_inhparent;
6648
6649         /*
6650          * Find all the inheritance information, excluding implicit inheritance
6651          * via partitioning.  We handle that case using getPartitions(), because
6652          * we want more information about partitions than just the parent-child
6653          * relationship.
6654          */
6655         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6656
6657         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6658
6659         ntups = PQntuples(res);
6660
6661         *numInherits = ntups;
6662
6663         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6664
6665         i_inhrelid = PQfnumber(res, "inhrelid");
6666         i_inhparent = PQfnumber(res, "inhparent");
6667
6668         for (i = 0; i < ntups; i++)
6669         {
6670                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6671                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6672         }
6673
6674         PQclear(res);
6675
6676         destroyPQExpBuffer(query);
6677
6678         return inhinfo;
6679 }
6680
6681 /*
6682  * getIndexes
6683  *        get information about every index on a dumpable table
6684  *
6685  * Note: index data is not returned directly to the caller, but it
6686  * does get entered into the DumpableObject tables.
6687  */
6688 void
6689 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6690 {
6691         int                     i,
6692                                 j;
6693         PQExpBuffer query = createPQExpBuffer();
6694         PGresult   *res;
6695         IndxInfo   *indxinfo;
6696         ConstraintInfo *constrinfo;
6697         int                     i_tableoid,
6698                                 i_oid,
6699                                 i_indexname,
6700                                 i_parentidx,
6701                                 i_indexdef,
6702                                 i_indnkeyatts,
6703                                 i_indnatts,
6704                                 i_indkey,
6705                                 i_indisclustered,
6706                                 i_indisreplident,
6707                                 i_contype,
6708                                 i_conname,
6709                                 i_condeferrable,
6710                                 i_condeferred,
6711                                 i_contableoid,
6712                                 i_conoid,
6713                                 i_condef,
6714                                 i_tablespace,
6715                                 i_indreloptions;
6716         int                     ntups;
6717
6718         for (i = 0; i < numTables; i++)
6719         {
6720                 TableInfo  *tbinfo = &tblinfo[i];
6721
6722                 if (!tbinfo->hasindex)
6723                         continue;
6724
6725                 /*
6726                  * Ignore indexes of tables whose definitions are not to be dumped.
6727                  *
6728                  * We also need indexes on partitioned tables which have partitions to
6729                  * be dumped, in order to dump the indexes on the partitions.
6730                  */
6731                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6732                         !tbinfo->interesting)
6733                         continue;
6734
6735                 if (g_verbose)
6736                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6737                                           tbinfo->dobj.namespace->dobj.name,
6738                                           tbinfo->dobj.name);
6739
6740                 /*
6741                  * The point of the messy-looking outer join is to find a constraint
6742                  * that is related by an internal dependency link to the index. If we
6743                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6744                  * assume an index won't have more than one internal dependency.
6745                  *
6746                  * As of 9.0 we don't need to look at pg_depend but can check for a
6747                  * match to pg_constraint.conindid.  The check on conrelid is
6748                  * redundant but useful because that column is indexed while conindid
6749                  * is not.
6750                  */
6751                 resetPQExpBuffer(query);
6752                 if (fout->remoteVersion >= 110000)
6753                 {
6754                         appendPQExpBuffer(query,
6755                                                           "SELECT t.tableoid, t.oid, "
6756                                                           "t.relname AS indexname, "
6757                                                           "inh.inhparent AS parentidx, "
6758                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6759                                                           "i.indnkeyatts AS indnkeyatts, "
6760                                                           "i.indnatts AS indnatts, "
6761                                                           "i.indkey, i.indisclustered, "
6762                                                           "i.indisreplident, "
6763                                                           "c.contype, c.conname, "
6764                                                           "c.condeferrable, c.condeferred, "
6765                                                           "c.tableoid AS contableoid, "
6766                                                           "c.oid AS conoid, "
6767                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6768                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6769                                                           "t.reloptions AS indreloptions "
6770                                                           "FROM pg_catalog.pg_index i "
6771                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6772                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6773                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6774                                                           "ON (i.indrelid = c.conrelid AND "
6775                                                           "i.indexrelid = c.conindid AND "
6776                                                           "c.contype IN ('p','u','x')) "
6777                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6778                                                           "ON (inh.inhrelid = indexrelid) "
6779                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6780                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6781                                                           "AND i.indisready "
6782                                                           "ORDER BY indexname",
6783                                                           tbinfo->dobj.catId.oid);
6784                 }
6785                 else if (fout->remoteVersion >= 90400)
6786                 {
6787                         /*
6788                          * the test on indisready is necessary in 9.2, and harmless in
6789                          * earlier/later versions
6790                          */
6791                         appendPQExpBuffer(query,
6792                                                           "SELECT t.tableoid, t.oid, "
6793                                                           "t.relname AS indexname, "
6794                                                           "0 AS parentidx, "
6795                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6796                                                           "i.indnatts AS indnkeyatts, "
6797                                                           "i.indnatts AS indnatts, "
6798                                                           "i.indkey, i.indisclustered, "
6799                                                           "i.indisreplident, "
6800                                                           "c.contype, c.conname, "
6801                                                           "c.condeferrable, c.condeferred, "
6802                                                           "c.tableoid AS contableoid, "
6803                                                           "c.oid AS conoid, "
6804                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6805                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6806                                                           "t.reloptions AS indreloptions "
6807                                                           "FROM pg_catalog.pg_index i "
6808                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6809                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6810                                                           "ON (i.indrelid = c.conrelid AND "
6811                                                           "i.indexrelid = c.conindid AND "
6812                                                           "c.contype IN ('p','u','x')) "
6813                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6814                                                           "AND i.indisvalid AND i.indisready "
6815                                                           "ORDER BY indexname",
6816                                                           tbinfo->dobj.catId.oid);
6817                 }
6818                 else if (fout->remoteVersion >= 90000)
6819                 {
6820                         /*
6821                          * the test on indisready is necessary in 9.2, and harmless in
6822                          * earlier/later versions
6823                          */
6824                         appendPQExpBuffer(query,
6825                                                           "SELECT t.tableoid, t.oid, "
6826                                                           "t.relname AS indexname, "
6827                                                           "0 AS parentidx, "
6828                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6829                                                           "i.indnatts AS indnkeyatts, "
6830                                                           "i.indnatts AS indnatts, "
6831                                                           "i.indkey, i.indisclustered, "
6832                                                           "false AS indisreplident, "
6833                                                           "c.contype, c.conname, "
6834                                                           "c.condeferrable, c.condeferred, "
6835                                                           "c.tableoid AS contableoid, "
6836                                                           "c.oid AS conoid, "
6837                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6838                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6839                                                           "t.reloptions AS indreloptions "
6840                                                           "FROM pg_catalog.pg_index i "
6841                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6842                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6843                                                           "ON (i.indrelid = c.conrelid AND "
6844                                                           "i.indexrelid = c.conindid AND "
6845                                                           "c.contype IN ('p','u','x')) "
6846                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6847                                                           "AND i.indisvalid AND i.indisready "
6848                                                           "ORDER BY indexname",
6849                                                           tbinfo->dobj.catId.oid);
6850                 }
6851                 else if (fout->remoteVersion >= 80200)
6852                 {
6853                         appendPQExpBuffer(query,
6854                                                           "SELECT t.tableoid, t.oid, "
6855                                                           "t.relname AS indexname, "
6856                                                           "0 AS parentidx, "
6857                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6858                                                           "i.indnatts AS indnkeyatts, "
6859                                                           "i.indnatts AS indnatts, "
6860                                                           "i.indkey, i.indisclustered, "
6861                                                           "false AS indisreplident, "
6862                                                           "c.contype, c.conname, "
6863                                                           "c.condeferrable, c.condeferred, "
6864                                                           "c.tableoid AS contableoid, "
6865                                                           "c.oid AS conoid, "
6866                                                           "null AS condef, "
6867                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6868                                                           "t.reloptions AS indreloptions "
6869                                                           "FROM pg_catalog.pg_index i "
6870                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6871                                                           "LEFT JOIN pg_catalog.pg_depend d "
6872                                                           "ON (d.classid = t.tableoid "
6873                                                           "AND d.objid = t.oid "
6874                                                           "AND d.deptype = 'i') "
6875                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6876                                                           "ON (d.refclassid = c.tableoid "
6877                                                           "AND d.refobjid = c.oid) "
6878                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6879                                                           "AND i.indisvalid "
6880                                                           "ORDER BY indexname",
6881                                                           tbinfo->dobj.catId.oid);
6882                 }
6883                 else
6884                 {
6885                         appendPQExpBuffer(query,
6886                                                           "SELECT t.tableoid, t.oid, "
6887                                                           "t.relname AS indexname, "
6888                                                           "0 AS parentidx, "
6889                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6890                                                           "t.relnatts AS indnkeyatts, "
6891                                                           "t.relnatts AS indnatts, "
6892                                                           "i.indkey, i.indisclustered, "
6893                                                           "false AS indisreplident, "
6894                                                           "c.contype, c.conname, "
6895                                                           "c.condeferrable, c.condeferred, "
6896                                                           "c.tableoid AS contableoid, "
6897                                                           "c.oid AS conoid, "
6898                                                           "null AS condef, "
6899                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6900                                                           "null AS indreloptions "
6901                                                           "FROM pg_catalog.pg_index i "
6902                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6903                                                           "LEFT JOIN pg_catalog.pg_depend d "
6904                                                           "ON (d.classid = t.tableoid "
6905                                                           "AND d.objid = t.oid "
6906                                                           "AND d.deptype = 'i') "
6907                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6908                                                           "ON (d.refclassid = c.tableoid "
6909                                                           "AND d.refobjid = c.oid) "
6910                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6911                                                           "ORDER BY indexname",
6912                                                           tbinfo->dobj.catId.oid);
6913                 }
6914
6915                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6916
6917                 ntups = PQntuples(res);
6918
6919                 i_tableoid = PQfnumber(res, "tableoid");
6920                 i_oid = PQfnumber(res, "oid");
6921                 i_indexname = PQfnumber(res, "indexname");
6922                 i_parentidx = PQfnumber(res, "parentidx");
6923                 i_indexdef = PQfnumber(res, "indexdef");
6924                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
6925                 i_indnatts = PQfnumber(res, "indnatts");
6926                 i_indkey = PQfnumber(res, "indkey");
6927                 i_indisclustered = PQfnumber(res, "indisclustered");
6928                 i_indisreplident = PQfnumber(res, "indisreplident");
6929                 i_contype = PQfnumber(res, "contype");
6930                 i_conname = PQfnumber(res, "conname");
6931                 i_condeferrable = PQfnumber(res, "condeferrable");
6932                 i_condeferred = PQfnumber(res, "condeferred");
6933                 i_contableoid = PQfnumber(res, "contableoid");
6934                 i_conoid = PQfnumber(res, "conoid");
6935                 i_condef = PQfnumber(res, "condef");
6936                 i_tablespace = PQfnumber(res, "tablespace");
6937                 i_indreloptions = PQfnumber(res, "indreloptions");
6938
6939                 tbinfo->indexes = indxinfo =
6940                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
6941                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6942                 tbinfo->numIndexes = ntups;
6943
6944                 for (j = 0; j < ntups; j++)
6945                 {
6946                         char            contype;
6947
6948                         indxinfo[j].dobj.objType = DO_INDEX;
6949                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6950                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6951                         AssignDumpId(&indxinfo[j].dobj);
6952                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
6953                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6954                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6955                         indxinfo[j].indextable = tbinfo;
6956                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
6957                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
6958                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
6959                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
6960                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
6961                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
6962                         parseOidArray(PQgetvalue(res, j, i_indkey),
6963                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
6964                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
6965                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
6966                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
6967                         contype = *(PQgetvalue(res, j, i_contype));
6968
6969                         if (contype == 'p' || contype == 'u' || contype == 'x')
6970                         {
6971                                 /*
6972                                  * If we found a constraint matching the index, create an
6973                                  * entry for it.
6974                                  */
6975                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
6976                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6977                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
6978                                 AssignDumpId(&constrinfo[j].dobj);
6979                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
6980                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6981                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6982                                 constrinfo[j].contable = tbinfo;
6983                                 constrinfo[j].condomain = NULL;
6984                                 constrinfo[j].contype = contype;
6985                                 if (contype == 'x')
6986                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
6987                                 else
6988                                         constrinfo[j].condef = NULL;
6989                                 constrinfo[j].confrelid = InvalidOid;
6990                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
6991                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
6992                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
6993                                 constrinfo[j].conislocal = true;
6994                                 constrinfo[j].separate = true;
6995
6996                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
6997                         }
6998                         else
6999                         {
7000                                 /* Plain secondary index */
7001                                 indxinfo[j].indexconstraint = 0;
7002                         }
7003                 }
7004
7005                 PQclear(res);
7006         }
7007
7008         destroyPQExpBuffer(query);
7009 }
7010
7011 /*
7012  * getExtendedStatistics
7013  *        get information about extended-statistics objects.
7014  *
7015  * Note: extended statistics data is not returned directly to the caller, but
7016  * it does get entered into the DumpableObject tables.
7017  */
7018 void
7019 getExtendedStatistics(Archive *fout)
7020 {
7021         PQExpBuffer query;
7022         PGresult   *res;
7023         StatsExtInfo *statsextinfo;
7024         int                     ntups;
7025         int                     i_tableoid;
7026         int                     i_oid;
7027         int                     i_stxname;
7028         int                     i_stxnamespace;
7029         int                     i_rolname;
7030         int                     i;
7031
7032         /* Extended statistics were new in v10 */
7033         if (fout->remoteVersion < 100000)
7034                 return;
7035
7036         query = createPQExpBuffer();
7037
7038         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7039                                           "stxnamespace, (%s stxowner) AS rolname "
7040                                           "FROM pg_catalog.pg_statistic_ext",
7041                                           username_subquery);
7042
7043         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7044
7045         ntups = PQntuples(res);
7046
7047         i_tableoid = PQfnumber(res, "tableoid");
7048         i_oid = PQfnumber(res, "oid");
7049         i_stxname = PQfnumber(res, "stxname");
7050         i_stxnamespace = PQfnumber(res, "stxnamespace");
7051         i_rolname = PQfnumber(res, "rolname");
7052
7053         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7054
7055         for (i = 0; i < ntups; i++)
7056         {
7057                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7058                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7059                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7060                 AssignDumpId(&statsextinfo[i].dobj);
7061                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7062                 statsextinfo[i].dobj.namespace =
7063                         findNamespace(fout,
7064                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7065                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7066
7067                 /* Decide whether we want to dump it */
7068                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7069
7070                 /* Stats objects do not currently have ACLs. */
7071                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7072         }
7073
7074         PQclear(res);
7075         destroyPQExpBuffer(query);
7076 }
7077
7078 /*
7079  * getConstraints
7080  *
7081  * Get info about constraints on dumpable tables.
7082  *
7083  * Currently handles foreign keys only.
7084  * Unique and primary key constraints are handled with indexes,
7085  * while check constraints are processed in getTableAttrs().
7086  */
7087 void
7088 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7089 {
7090         int                     i,
7091                                 j;
7092         ConstraintInfo *constrinfo;
7093         PQExpBuffer query;
7094         PGresult   *res;
7095         int                     i_contableoid,
7096                                 i_conoid,
7097                                 i_conname,
7098                                 i_confrelid,
7099                                 i_condef;
7100         int                     ntups;
7101
7102         query = createPQExpBuffer();
7103
7104         for (i = 0; i < numTables; i++)
7105         {
7106                 TableInfo  *tbinfo = &tblinfo[i];
7107
7108                 /*
7109                  * For partitioned tables, foreign keys have no triggers so they must
7110                  * be included anyway in case some foreign keys are defined.
7111                  */
7112                 if ((!tbinfo->hastriggers &&
7113                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7114                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7115                         continue;
7116
7117                 if (g_verbose)
7118                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7119                                           tbinfo->dobj.namespace->dobj.name,
7120                                           tbinfo->dobj.name);
7121
7122                 resetPQExpBuffer(query);
7123                 if (fout->remoteVersion >= 110000)
7124                         appendPQExpBuffer(query,
7125                                                           "SELECT tableoid, oid, conname, confrelid, "
7126                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7127                                                           "FROM pg_catalog.pg_constraint "
7128                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7129                                                           "AND conparentid = 0 "
7130                                                           "AND contype = 'f'",
7131                                                           tbinfo->dobj.catId.oid);
7132                 else
7133                         appendPQExpBuffer(query,
7134                                                           "SELECT tableoid, oid, conname, confrelid, "
7135                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7136                                                           "FROM pg_catalog.pg_constraint "
7137                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7138                                                           "AND contype = 'f'",
7139                                                           tbinfo->dobj.catId.oid);
7140                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7141
7142                 ntups = PQntuples(res);
7143
7144                 i_contableoid = PQfnumber(res, "tableoid");
7145                 i_conoid = PQfnumber(res, "oid");
7146                 i_conname = PQfnumber(res, "conname");
7147                 i_confrelid = PQfnumber(res, "confrelid");
7148                 i_condef = PQfnumber(res, "condef");
7149
7150                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7151
7152                 for (j = 0; j < ntups; j++)
7153                 {
7154                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7155                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7156                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7157                         AssignDumpId(&constrinfo[j].dobj);
7158                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7159                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7160                         constrinfo[j].contable = tbinfo;
7161                         constrinfo[j].condomain = NULL;
7162                         constrinfo[j].contype = 'f';
7163                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7164                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7165                         constrinfo[j].conindex = 0;
7166                         constrinfo[j].condeferrable = false;
7167                         constrinfo[j].condeferred = false;
7168                         constrinfo[j].conislocal = true;
7169                         constrinfo[j].separate = true;
7170                 }
7171
7172                 PQclear(res);
7173         }
7174
7175         destroyPQExpBuffer(query);
7176 }
7177
7178 /*
7179  * getDomainConstraints
7180  *
7181  * Get info about constraints on a domain.
7182  */
7183 static void
7184 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7185 {
7186         int                     i;
7187         ConstraintInfo *constrinfo;
7188         PQExpBuffer query;
7189         PGresult   *res;
7190         int                     i_tableoid,
7191                                 i_oid,
7192                                 i_conname,
7193                                 i_consrc;
7194         int                     ntups;
7195
7196         query = createPQExpBuffer();
7197
7198         if (fout->remoteVersion >= 90100)
7199                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7200                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7201                                                   "convalidated "
7202                                                   "FROM pg_catalog.pg_constraint "
7203                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7204                                                   "ORDER BY conname",
7205                                                   tyinfo->dobj.catId.oid);
7206
7207         else
7208                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7209                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7210                                                   "true as convalidated "
7211                                                   "FROM pg_catalog.pg_constraint "
7212                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7213                                                   "ORDER BY conname",
7214                                                   tyinfo->dobj.catId.oid);
7215
7216         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7217
7218         ntups = PQntuples(res);
7219
7220         i_tableoid = PQfnumber(res, "tableoid");
7221         i_oid = PQfnumber(res, "oid");
7222         i_conname = PQfnumber(res, "conname");
7223         i_consrc = PQfnumber(res, "consrc");
7224
7225         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7226
7227         tyinfo->nDomChecks = ntups;
7228         tyinfo->domChecks = constrinfo;
7229
7230         for (i = 0; i < ntups; i++)
7231         {
7232                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7233
7234                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7235                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7236                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7237                 AssignDumpId(&constrinfo[i].dobj);
7238                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7239                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7240                 constrinfo[i].contable = NULL;
7241                 constrinfo[i].condomain = tyinfo;
7242                 constrinfo[i].contype = 'c';
7243                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7244                 constrinfo[i].confrelid = InvalidOid;
7245                 constrinfo[i].conindex = 0;
7246                 constrinfo[i].condeferrable = false;
7247                 constrinfo[i].condeferred = false;
7248                 constrinfo[i].conislocal = true;
7249
7250                 constrinfo[i].separate = !validated;
7251
7252                 /*
7253                  * Make the domain depend on the constraint, ensuring it won't be
7254                  * output till any constraint dependencies are OK.  If the constraint
7255                  * has not been validated, it's going to be dumped after the domain
7256                  * anyway, so this doesn't matter.
7257                  */
7258                 if (validated)
7259                         addObjectDependency(&tyinfo->dobj,
7260                                                                 constrinfo[i].dobj.dumpId);
7261         }
7262
7263         PQclear(res);
7264
7265         destroyPQExpBuffer(query);
7266 }
7267
7268 /*
7269  * getRules
7270  *        get basic information about every rule in the system
7271  *
7272  * numRules is set to the number of rules read in
7273  */
7274 RuleInfo *
7275 getRules(Archive *fout, int *numRules)
7276 {
7277         PGresult   *res;
7278         int                     ntups;
7279         int                     i;
7280         PQExpBuffer query = createPQExpBuffer();
7281         RuleInfo   *ruleinfo;
7282         int                     i_tableoid;
7283         int                     i_oid;
7284         int                     i_rulename;
7285         int                     i_ruletable;
7286         int                     i_ev_type;
7287         int                     i_is_instead;
7288         int                     i_ev_enabled;
7289
7290         if (fout->remoteVersion >= 80300)
7291         {
7292                 appendPQExpBufferStr(query, "SELECT "
7293                                                          "tableoid, oid, rulename, "
7294                                                          "ev_class AS ruletable, ev_type, is_instead, "
7295                                                          "ev_enabled "
7296                                                          "FROM pg_rewrite "
7297                                                          "ORDER BY oid");
7298         }
7299         else
7300         {
7301                 appendPQExpBufferStr(query, "SELECT "
7302                                                          "tableoid, oid, rulename, "
7303                                                          "ev_class AS ruletable, ev_type, is_instead, "
7304                                                          "'O'::char AS ev_enabled "
7305                                                          "FROM pg_rewrite "
7306                                                          "ORDER BY oid");
7307         }
7308
7309         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7310
7311         ntups = PQntuples(res);
7312
7313         *numRules = ntups;
7314
7315         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7316
7317         i_tableoid = PQfnumber(res, "tableoid");
7318         i_oid = PQfnumber(res, "oid");
7319         i_rulename = PQfnumber(res, "rulename");
7320         i_ruletable = PQfnumber(res, "ruletable");
7321         i_ev_type = PQfnumber(res, "ev_type");
7322         i_is_instead = PQfnumber(res, "is_instead");
7323         i_ev_enabled = PQfnumber(res, "ev_enabled");
7324
7325         for (i = 0; i < ntups; i++)
7326         {
7327                 Oid                     ruletableoid;
7328
7329                 ruleinfo[i].dobj.objType = DO_RULE;
7330                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7331                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7332                 AssignDumpId(&ruleinfo[i].dobj);
7333                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7334                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7335                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7336                 if (ruleinfo[i].ruletable == NULL)
7337                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7338                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7339                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7340                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7341                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7342                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7343                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7344                 if (ruleinfo[i].ruletable)
7345                 {
7346                         /*
7347                          * If the table is a view or materialized view, force its ON
7348                          * SELECT rule to be sorted before the view itself --- this
7349                          * ensures that any dependencies for the rule affect the table's
7350                          * positioning. Other rules are forced to appear after their
7351                          * table.
7352                          */
7353                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7354                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7355                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7356                         {
7357                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7358                                                                         ruleinfo[i].dobj.dumpId);
7359                                 /* We'll merge the rule into CREATE VIEW, if possible */
7360                                 ruleinfo[i].separate = false;
7361                         }
7362                         else
7363                         {
7364                                 addObjectDependency(&ruleinfo[i].dobj,
7365                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7366                                 ruleinfo[i].separate = true;
7367                         }
7368                 }
7369                 else
7370                         ruleinfo[i].separate = true;
7371         }
7372
7373         PQclear(res);
7374
7375         destroyPQExpBuffer(query);
7376
7377         return ruleinfo;
7378 }
7379
7380 /*
7381  * getTriggers
7382  *        get information about every trigger on a dumpable table
7383  *
7384  * Note: trigger data is not returned directly to the caller, but it
7385  * does get entered into the DumpableObject tables.
7386  */
7387 void
7388 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7389 {
7390         int                     i,
7391                                 j;
7392         PQExpBuffer query = createPQExpBuffer();
7393         PGresult   *res;
7394         TriggerInfo *tginfo;
7395         int                     i_tableoid,
7396                                 i_oid,
7397                                 i_tgname,
7398                                 i_tgfname,
7399                                 i_tgtype,
7400                                 i_tgnargs,
7401                                 i_tgargs,
7402                                 i_tgisconstraint,
7403                                 i_tgconstrname,
7404                                 i_tgconstrrelid,
7405                                 i_tgconstrrelname,
7406                                 i_tgenabled,
7407                                 i_tgdeferrable,
7408                                 i_tginitdeferred,
7409                                 i_tgdef;
7410         int                     ntups;
7411
7412         for (i = 0; i < numTables; i++)
7413         {
7414                 TableInfo  *tbinfo = &tblinfo[i];
7415
7416                 if (!tbinfo->hastriggers ||
7417                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7418                         continue;
7419
7420                 if (g_verbose)
7421                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7422                                           tbinfo->dobj.namespace->dobj.name,
7423                                           tbinfo->dobj.name);
7424
7425                 resetPQExpBuffer(query);
7426                 if (fout->remoteVersion >= 90000)
7427                 {
7428                         /*
7429                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7430                          * could result in non-forward-compatible dumps of WHEN clauses
7431                          * due to under-parenthesization.
7432                          */
7433                         appendPQExpBuffer(query,
7434                                                           "SELECT tgname, "
7435                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7436                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7437                                                           "tgenabled, tableoid, oid "
7438                                                           "FROM pg_catalog.pg_trigger t "
7439                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7440                                                           "AND NOT tgisinternal",
7441                                                           tbinfo->dobj.catId.oid);
7442                 }
7443                 else if (fout->remoteVersion >= 80300)
7444                 {
7445                         /*
7446                          * We ignore triggers that are tied to a foreign-key constraint
7447                          */
7448                         appendPQExpBuffer(query,
7449                                                           "SELECT tgname, "
7450                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7451                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7452                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7453                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7454                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7455                                                           "FROM pg_catalog.pg_trigger t "
7456                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7457                                                           "AND tgconstraint = 0",
7458                                                           tbinfo->dobj.catId.oid);
7459                 }
7460                 else
7461                 {
7462                         /*
7463                          * We ignore triggers that are tied to a foreign-key constraint,
7464                          * but in these versions we have to grovel through pg_constraint
7465                          * to find out
7466                          */
7467                         appendPQExpBuffer(query,
7468                                                           "SELECT tgname, "
7469                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7470                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7471                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7472                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7473                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7474                                                           "FROM pg_catalog.pg_trigger t "
7475                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7476                                                           "AND (NOT tgisconstraint "
7477                                                           " OR NOT EXISTS"
7478                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7479                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7480                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7481                                                           tbinfo->dobj.catId.oid);
7482                 }
7483
7484                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7485
7486                 ntups = PQntuples(res);
7487
7488                 i_tableoid = PQfnumber(res, "tableoid");
7489                 i_oid = PQfnumber(res, "oid");
7490                 i_tgname = PQfnumber(res, "tgname");
7491                 i_tgfname = PQfnumber(res, "tgfname");
7492                 i_tgtype = PQfnumber(res, "tgtype");
7493                 i_tgnargs = PQfnumber(res, "tgnargs");
7494                 i_tgargs = PQfnumber(res, "tgargs");
7495                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7496                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7497                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7498                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7499                 i_tgenabled = PQfnumber(res, "tgenabled");
7500                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7501                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7502                 i_tgdef = PQfnumber(res, "tgdef");
7503
7504                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7505
7506                 tbinfo->numTriggers = ntups;
7507                 tbinfo->triggers = tginfo;
7508
7509                 for (j = 0; j < ntups; j++)
7510                 {
7511                         tginfo[j].dobj.objType = DO_TRIGGER;
7512                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7513                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7514                         AssignDumpId(&tginfo[j].dobj);
7515                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7516                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7517                         tginfo[j].tgtable = tbinfo;
7518                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7519                         if (i_tgdef >= 0)
7520                         {
7521                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7522
7523                                 /* remaining fields are not valid if we have tgdef */
7524                                 tginfo[j].tgfname = NULL;
7525                                 tginfo[j].tgtype = 0;
7526                                 tginfo[j].tgnargs = 0;
7527                                 tginfo[j].tgargs = NULL;
7528                                 tginfo[j].tgisconstraint = false;
7529                                 tginfo[j].tgdeferrable = false;
7530                                 tginfo[j].tginitdeferred = false;
7531                                 tginfo[j].tgconstrname = NULL;
7532                                 tginfo[j].tgconstrrelid = InvalidOid;
7533                                 tginfo[j].tgconstrrelname = NULL;
7534                         }
7535                         else
7536                         {
7537                                 tginfo[j].tgdef = NULL;
7538
7539                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7540                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7541                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7542                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7543                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7544                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7545                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7546
7547                                 if (tginfo[j].tgisconstraint)
7548                                 {
7549                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7550                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7551                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7552                                         {
7553                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7554                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7555                                                                                   tginfo[j].dobj.name,
7556                                                                                   tbinfo->dobj.name,
7557                                                                                   tginfo[j].tgconstrrelid);
7558                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7559                                         }
7560                                         else
7561                                                 tginfo[j].tgconstrrelname = NULL;
7562                                 }
7563                                 else
7564                                 {
7565                                         tginfo[j].tgconstrname = NULL;
7566                                         tginfo[j].tgconstrrelid = InvalidOid;
7567                                         tginfo[j].tgconstrrelname = NULL;
7568                                 }
7569                         }
7570                 }
7571
7572                 PQclear(res);
7573         }
7574
7575         destroyPQExpBuffer(query);
7576 }
7577
7578 /*
7579  * getEventTriggers
7580  *        get information about event triggers
7581  */
7582 EventTriggerInfo *
7583 getEventTriggers(Archive *fout, int *numEventTriggers)
7584 {
7585         int                     i;
7586         PQExpBuffer query;
7587         PGresult   *res;
7588         EventTriggerInfo *evtinfo;
7589         int                     i_tableoid,
7590                                 i_oid,
7591                                 i_evtname,
7592                                 i_evtevent,
7593                                 i_evtowner,
7594                                 i_evttags,
7595                                 i_evtfname,
7596                                 i_evtenabled;
7597         int                     ntups;
7598
7599         /* Before 9.3, there are no event triggers */
7600         if (fout->remoteVersion < 90300)
7601         {
7602                 *numEventTriggers = 0;
7603                 return NULL;
7604         }
7605
7606         query = createPQExpBuffer();
7607
7608         appendPQExpBuffer(query,
7609                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7610                                           "evtevent, (%s evtowner) AS evtowner, "
7611                                           "array_to_string(array("
7612                                           "select quote_literal(x) "
7613                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7614                                           "e.evtfoid::regproc as evtfname "
7615                                           "FROM pg_event_trigger e "
7616                                           "ORDER BY e.oid",
7617                                           username_subquery);
7618
7619         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7620
7621         ntups = PQntuples(res);
7622
7623         *numEventTriggers = ntups;
7624
7625         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7626
7627         i_tableoid = PQfnumber(res, "tableoid");
7628         i_oid = PQfnumber(res, "oid");
7629         i_evtname = PQfnumber(res, "evtname");
7630         i_evtevent = PQfnumber(res, "evtevent");
7631         i_evtowner = PQfnumber(res, "evtowner");
7632         i_evttags = PQfnumber(res, "evttags");
7633         i_evtfname = PQfnumber(res, "evtfname");
7634         i_evtenabled = PQfnumber(res, "evtenabled");
7635
7636         for (i = 0; i < ntups; i++)
7637         {
7638                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7639                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7640                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7641                 AssignDumpId(&evtinfo[i].dobj);
7642                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7643                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7644                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7645                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7646                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7647                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7648                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7649
7650                 /* Decide whether we want to dump it */
7651                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7652
7653                 /* Event Triggers do not currently have ACLs. */
7654                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7655         }
7656
7657         PQclear(res);
7658
7659         destroyPQExpBuffer(query);
7660
7661         return evtinfo;
7662 }
7663
7664 /*
7665  * getProcLangs
7666  *        get basic information about every procedural language in the system
7667  *
7668  * numProcLangs is set to the number of langs read in
7669  *
7670  * NB: this must run after getFuncs() because we assume we can do
7671  * findFuncByOid().
7672  */
7673 ProcLangInfo *
7674 getProcLangs(Archive *fout, int *numProcLangs)
7675 {
7676         DumpOptions *dopt = fout->dopt;
7677         PGresult   *res;
7678         int                     ntups;
7679         int                     i;
7680         PQExpBuffer query = createPQExpBuffer();
7681         ProcLangInfo *planginfo;
7682         int                     i_tableoid;
7683         int                     i_oid;
7684         int                     i_lanname;
7685         int                     i_lanpltrusted;
7686         int                     i_lanplcallfoid;
7687         int                     i_laninline;
7688         int                     i_lanvalidator;
7689         int                     i_lanacl;
7690         int                     i_rlanacl;
7691         int                     i_initlanacl;
7692         int                     i_initrlanacl;
7693         int                     i_lanowner;
7694
7695         if (fout->remoteVersion >= 90600)
7696         {
7697                 PQExpBuffer acl_subquery = createPQExpBuffer();
7698                 PQExpBuffer racl_subquery = createPQExpBuffer();
7699                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7700                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7701
7702                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7703                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7704                                                 dopt->binary_upgrade);
7705
7706                 /* pg_language has a laninline column */
7707                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7708                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7709                                                   "l.laninline, l.lanvalidator, "
7710                                                   "%s AS lanacl, "
7711                                                   "%s AS rlanacl, "
7712                                                   "%s AS initlanacl, "
7713                                                   "%s AS initrlanacl, "
7714                                                   "(%s l.lanowner) AS lanowner "
7715                                                   "FROM pg_language l "
7716                                                   "LEFT JOIN pg_init_privs pip ON "
7717                                                   "(l.oid = pip.objoid "
7718                                                   "AND pip.classoid = 'pg_language'::regclass "
7719                                                   "AND pip.objsubid = 0) "
7720                                                   "WHERE l.lanispl "
7721                                                   "ORDER BY l.oid",
7722                                                   acl_subquery->data,
7723                                                   racl_subquery->data,
7724                                                   initacl_subquery->data,
7725                                                   initracl_subquery->data,
7726                                                   username_subquery);
7727
7728                 destroyPQExpBuffer(acl_subquery);
7729                 destroyPQExpBuffer(racl_subquery);
7730                 destroyPQExpBuffer(initacl_subquery);
7731                 destroyPQExpBuffer(initracl_subquery);
7732         }
7733         else if (fout->remoteVersion >= 90000)
7734         {
7735                 /* pg_language has a laninline column */
7736                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7737                                                   "lanname, lanpltrusted, lanplcallfoid, "
7738                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7739                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7740                                                   "(%s lanowner) AS lanowner "
7741                                                   "FROM pg_language "
7742                                                   "WHERE lanispl "
7743                                                   "ORDER BY oid",
7744                                                   username_subquery);
7745         }
7746         else if (fout->remoteVersion >= 80300)
7747         {
7748                 /* pg_language has a lanowner column */
7749                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7750                                                   "lanname, lanpltrusted, lanplcallfoid, "
7751                                                   "0 AS laninline, lanvalidator, lanacl, "
7752                                                   "NULL AS rlanacl, "
7753                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7754                                                   "(%s lanowner) AS lanowner "
7755                                                   "FROM pg_language "
7756                                                   "WHERE lanispl "
7757                                                   "ORDER BY oid",
7758                                                   username_subquery);
7759         }
7760         else if (fout->remoteVersion >= 80100)
7761         {
7762                 /* Languages are owned by the bootstrap superuser, OID 10 */
7763                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7764                                                   "lanname, lanpltrusted, lanplcallfoid, "
7765                                                   "0 AS laninline, lanvalidator, lanacl, "
7766                                                   "NULL AS rlanacl, "
7767                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7768                                                   "(%s '10') AS lanowner "
7769                                                   "FROM pg_language "
7770                                                   "WHERE lanispl "
7771                                                   "ORDER BY oid",
7772                                                   username_subquery);
7773         }
7774         else
7775         {
7776                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7777                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7778                                                   "lanname, lanpltrusted, lanplcallfoid, "
7779                                                   "0 AS laninline, lanvalidator, lanacl, "
7780                                                   "NULL AS rlanacl, "
7781                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7782                                                   "(%s '1') AS lanowner "
7783                                                   "FROM pg_language "
7784                                                   "WHERE lanispl "
7785                                                   "ORDER BY oid",
7786                                                   username_subquery);
7787         }
7788
7789         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7790
7791         ntups = PQntuples(res);
7792
7793         *numProcLangs = ntups;
7794
7795         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7796
7797         i_tableoid = PQfnumber(res, "tableoid");
7798         i_oid = PQfnumber(res, "oid");
7799         i_lanname = PQfnumber(res, "lanname");
7800         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7801         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7802         i_laninline = PQfnumber(res, "laninline");
7803         i_lanvalidator = PQfnumber(res, "lanvalidator");
7804         i_lanacl = PQfnumber(res, "lanacl");
7805         i_rlanacl = PQfnumber(res, "rlanacl");
7806         i_initlanacl = PQfnumber(res, "initlanacl");
7807         i_initrlanacl = PQfnumber(res, "initrlanacl");
7808         i_lanowner = PQfnumber(res, "lanowner");
7809
7810         for (i = 0; i < ntups; i++)
7811         {
7812                 planginfo[i].dobj.objType = DO_PROCLANG;
7813                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7814                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7815                 AssignDumpId(&planginfo[i].dobj);
7816
7817                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7818                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7819                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7820                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7821                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7822                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7823                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7824                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7825                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7826                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7827
7828                 /* Decide whether we want to dump it */
7829                 selectDumpableProcLang(&(planginfo[i]), fout);
7830
7831                 /* Do not try to dump ACL if no ACL exists. */
7832                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7833                         PQgetisnull(res, i, i_initlanacl) &&
7834                         PQgetisnull(res, i, i_initrlanacl))
7835                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7836         }
7837
7838         PQclear(res);
7839
7840         destroyPQExpBuffer(query);
7841
7842         return planginfo;
7843 }
7844
7845 /*
7846  * getCasts
7847  *        get basic information about every cast in the system
7848  *
7849  * numCasts is set to the number of casts read in
7850  */
7851 CastInfo *
7852 getCasts(Archive *fout, int *numCasts)
7853 {
7854         PGresult   *res;
7855         int                     ntups;
7856         int                     i;
7857         PQExpBuffer query = createPQExpBuffer();
7858         CastInfo   *castinfo;
7859         int                     i_tableoid;
7860         int                     i_oid;
7861         int                     i_castsource;
7862         int                     i_casttarget;
7863         int                     i_castfunc;
7864         int                     i_castcontext;
7865         int                     i_castmethod;
7866
7867         if (fout->remoteVersion >= 80400)
7868         {
7869                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7870                                                          "castsource, casttarget, castfunc, castcontext, "
7871                                                          "castmethod "
7872                                                          "FROM pg_cast ORDER BY 3,4");
7873         }
7874         else
7875         {
7876                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7877                                                          "castsource, casttarget, castfunc, castcontext, "
7878                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7879                                                          "FROM pg_cast ORDER BY 3,4");
7880         }
7881
7882         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7883
7884         ntups = PQntuples(res);
7885
7886         *numCasts = ntups;
7887
7888         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7889
7890         i_tableoid = PQfnumber(res, "tableoid");
7891         i_oid = PQfnumber(res, "oid");
7892         i_castsource = PQfnumber(res, "castsource");
7893         i_casttarget = PQfnumber(res, "casttarget");
7894         i_castfunc = PQfnumber(res, "castfunc");
7895         i_castcontext = PQfnumber(res, "castcontext");
7896         i_castmethod = PQfnumber(res, "castmethod");
7897
7898         for (i = 0; i < ntups; i++)
7899         {
7900                 PQExpBufferData namebuf;
7901                 TypeInfo   *sTypeInfo;
7902                 TypeInfo   *tTypeInfo;
7903
7904                 castinfo[i].dobj.objType = DO_CAST;
7905                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7906                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7907                 AssignDumpId(&castinfo[i].dobj);
7908                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7909                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7910                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7911                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7912                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7913
7914                 /*
7915                  * Try to name cast as concatenation of typnames.  This is only used
7916                  * for purposes of sorting.  If we fail to find either type, the name
7917                  * will be an empty string.
7918                  */
7919                 initPQExpBuffer(&namebuf);
7920                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
7921                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7922                 if (sTypeInfo && tTypeInfo)
7923                         appendPQExpBuffer(&namebuf, "%s %s",
7924                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7925                 castinfo[i].dobj.name = namebuf.data;
7926
7927                 /* Decide whether we want to dump it */
7928                 selectDumpableCast(&(castinfo[i]), fout);
7929
7930                 /* Casts do not currently have ACLs. */
7931                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7932         }
7933
7934         PQclear(res);
7935
7936         destroyPQExpBuffer(query);
7937
7938         return castinfo;
7939 }
7940
7941 static char *
7942 get_language_name(Archive *fout, Oid langid)
7943 {
7944         PQExpBuffer query;
7945         PGresult   *res;
7946         char       *lanname;
7947
7948         query = createPQExpBuffer();
7949         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
7950         res = ExecuteSqlQueryForSingleRow(fout, query->data);
7951         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
7952         destroyPQExpBuffer(query);
7953         PQclear(res);
7954
7955         return lanname;
7956 }
7957
7958 /*
7959  * getTransforms
7960  *        get basic information about every transform in the system
7961  *
7962  * numTransforms is set to the number of transforms read in
7963  */
7964 TransformInfo *
7965 getTransforms(Archive *fout, int *numTransforms)
7966 {
7967         PGresult   *res;
7968         int                     ntups;
7969         int                     i;
7970         PQExpBuffer query;
7971         TransformInfo *transforminfo;
7972         int                     i_tableoid;
7973         int                     i_oid;
7974         int                     i_trftype;
7975         int                     i_trflang;
7976         int                     i_trffromsql;
7977         int                     i_trftosql;
7978
7979         /* Transforms didn't exist pre-9.5 */
7980         if (fout->remoteVersion < 90500)
7981         {
7982                 *numTransforms = 0;
7983                 return NULL;
7984         }
7985
7986         query = createPQExpBuffer();
7987
7988         appendPQExpBuffer(query, "SELECT tableoid, oid, "
7989                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
7990                                           "FROM pg_transform "
7991                                           "ORDER BY 3,4");
7992
7993         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7994
7995         ntups = PQntuples(res);
7996
7997         *numTransforms = ntups;
7998
7999         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8000
8001         i_tableoid = PQfnumber(res, "tableoid");
8002         i_oid = PQfnumber(res, "oid");
8003         i_trftype = PQfnumber(res, "trftype");
8004         i_trflang = PQfnumber(res, "trflang");
8005         i_trffromsql = PQfnumber(res, "trffromsql");
8006         i_trftosql = PQfnumber(res, "trftosql");
8007
8008         for (i = 0; i < ntups; i++)
8009         {
8010                 PQExpBufferData namebuf;
8011                 TypeInfo   *typeInfo;
8012                 char       *lanname;
8013
8014                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8015                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8016                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8017                 AssignDumpId(&transforminfo[i].dobj);
8018                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8019                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8020                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8021                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8022
8023                 /*
8024                  * Try to name transform as concatenation of type and language name.
8025                  * This is only used for purposes of sorting.  If we fail to find
8026                  * either, the name will be an empty string.
8027                  */
8028                 initPQExpBuffer(&namebuf);
8029                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8030                 lanname = get_language_name(fout, transforminfo[i].trflang);
8031                 if (typeInfo && lanname)
8032                         appendPQExpBuffer(&namebuf, "%s %s",
8033                                                           typeInfo->dobj.name, lanname);
8034                 transforminfo[i].dobj.name = namebuf.data;
8035                 free(lanname);
8036
8037                 /* Decide whether we want to dump it */
8038                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8039         }
8040
8041         PQclear(res);
8042
8043         destroyPQExpBuffer(query);
8044
8045         return transforminfo;
8046 }
8047
8048 /*
8049  * getTableAttrs -
8050  *        for each interesting table, read info about its attributes
8051  *        (names, types, default values, CHECK constraints, etc)
8052  *
8053  * This is implemented in a very inefficient way right now, looping
8054  * through the tblinfo and doing a join per table to find the attrs and their
8055  * types.  However, because we want type names and so forth to be named
8056  * relative to the schema of each table, we couldn't do it in just one
8057  * query.  (Maybe one query per schema?)
8058  *
8059  *      modifies tblinfo
8060  */
8061 void
8062 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8063 {
8064         DumpOptions *dopt = fout->dopt;
8065         int                     i,
8066                                 j;
8067         PQExpBuffer q = createPQExpBuffer();
8068         int                     i_attnum;
8069         int                     i_attname;
8070         int                     i_atttypname;
8071         int                     i_atttypmod;
8072         int                     i_attstattarget;
8073         int                     i_attstorage;
8074         int                     i_typstorage;
8075         int                     i_attnotnull;
8076         int                     i_atthasdef;
8077         int                     i_attidentity;
8078         int                     i_attisdropped;
8079         int                     i_attlen;
8080         int                     i_attalign;
8081         int                     i_attislocal;
8082         int                     i_attoptions;
8083         int                     i_attcollation;
8084         int                     i_attfdwoptions;
8085         int                     i_attmissingval;
8086         PGresult   *res;
8087         int                     ntups;
8088         bool            hasdefaults;
8089
8090         for (i = 0; i < numTables; i++)
8091         {
8092                 TableInfo  *tbinfo = &tblinfo[i];
8093
8094                 /* Don't bother to collect info for sequences */
8095                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8096                         continue;
8097
8098                 /* Don't bother with uninteresting tables, either */
8099                 if (!tbinfo->interesting)
8100                         continue;
8101
8102                 /* find all the user attributes and their types */
8103
8104                 /*
8105                  * we must read the attribute names in attribute number order! because
8106                  * we will use the attnum to index into the attnames array later.
8107                  */
8108                 if (g_verbose)
8109                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8110                                           tbinfo->dobj.namespace->dobj.name,
8111                                           tbinfo->dobj.name);
8112
8113                 resetPQExpBuffer(q);
8114
8115                 appendPQExpBuffer(q,
8116                                                   "SELECT\n"
8117                                                   "a.attnum,\n"
8118                                                   "a.attname,\n"
8119                                                   "a.atttypmod,\n"
8120                                                   "a.attstattarget,\n"
8121                                                   "a.attstorage,\n"
8122                                                   "t.typstorage,\n"
8123                                                   "a.attnotnull,\n"
8124                                                   "a.atthasdef,\n"
8125                                                   "a.attisdropped,\n"
8126                                                   "a.attlen,\n"
8127                                                   "a.attalign,\n"
8128                                                   "a.attislocal,\n"
8129                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8130
8131                 if (fout->remoteVersion >= 110000)
8132                         appendPQExpBuffer(q,
8133                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8134                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8135                 else
8136                         appendPQExpBuffer(q,
8137                                                           "NULL AS attmissingval,\n");
8138
8139                 if (fout->remoteVersion >= 100000)
8140                         appendPQExpBuffer(q,
8141                                                           "a.attidentity,\n");
8142                 else
8143                         appendPQExpBuffer(q,
8144                                                           "'' AS attidentity,\n");
8145
8146                 if (fout->remoteVersion >= 90200)
8147                         appendPQExpBuffer(q,
8148                                                           "pg_catalog.array_to_string(ARRAY("
8149                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8150                                                           "' ' || pg_catalog.quote_literal(option_value) "
8151                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8152                                                           "ORDER BY option_name"
8153                                                           "), E',\n    ') AS attfdwoptions,\n");
8154                 else
8155                         appendPQExpBuffer(q,
8156                                                           "'' AS attfdwoptions,\n");
8157
8158                 if (fout->remoteVersion >= 90100)
8159                 {
8160                         /*
8161                          * Since we only want to dump COLLATE clauses for attributes whose
8162                          * collation is different from their type's default, we use a CASE
8163                          * here to suppress uninteresting attcollations cheaply.
8164                          */
8165                         appendPQExpBuffer(q,
8166                                                           "CASE WHEN a.attcollation <> t.typcollation "
8167                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8168                 }
8169                 else
8170                         appendPQExpBuffer(q,
8171                                                           "0 AS attcollation,\n");
8172
8173                 if (fout->remoteVersion >= 90000)
8174                         appendPQExpBuffer(q,
8175                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8176                 else
8177                         appendPQExpBuffer(q,
8178                                                           "'' AS attoptions\n");
8179
8180                 /* need left join here to not fail on dropped columns ... */
8181                 appendPQExpBuffer(q,
8182                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8183                                                   "ON a.atttypid = t.oid\n"
8184                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8185                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8186                                                   "ORDER BY a.attnum",
8187                                                   tbinfo->dobj.catId.oid);
8188
8189                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8190
8191                 ntups = PQntuples(res);
8192
8193                 i_attnum = PQfnumber(res, "attnum");
8194                 i_attname = PQfnumber(res, "attname");
8195                 i_atttypname = PQfnumber(res, "atttypname");
8196                 i_atttypmod = PQfnumber(res, "atttypmod");
8197                 i_attstattarget = PQfnumber(res, "attstattarget");
8198                 i_attstorage = PQfnumber(res, "attstorage");
8199                 i_typstorage = PQfnumber(res, "typstorage");
8200                 i_attnotnull = PQfnumber(res, "attnotnull");
8201                 i_atthasdef = PQfnumber(res, "atthasdef");
8202                 i_attidentity = PQfnumber(res, "attidentity");
8203                 i_attisdropped = PQfnumber(res, "attisdropped");
8204                 i_attlen = PQfnumber(res, "attlen");
8205                 i_attalign = PQfnumber(res, "attalign");
8206                 i_attislocal = PQfnumber(res, "attislocal");
8207                 i_attoptions = PQfnumber(res, "attoptions");
8208                 i_attcollation = PQfnumber(res, "attcollation");
8209                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8210                 i_attmissingval = PQfnumber(res, "attmissingval");
8211
8212                 tbinfo->numatts = ntups;
8213                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8214                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8215                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8216                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8217                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8218                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8219                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8220                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8221                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8222                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8223                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8224                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8225                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8226                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8227                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8228                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8229                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8230                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8231                 hasdefaults = false;
8232
8233                 for (j = 0; j < ntups; j++)
8234                 {
8235                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8236                                 exit_horribly(NULL,
8237                                                           "invalid column numbering in table \"%s\"\n",
8238                                                           tbinfo->dobj.name);
8239                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8240                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8241                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8242                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8243                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8244                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8245                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8246                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8247                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8248                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8249                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8250                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8251                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8252                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8253                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8254                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8255                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8256                         tbinfo->attrdefs[j] = NULL; /* fix below */
8257                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8258                                 hasdefaults = true;
8259                         /* these flags will be set in flagInhAttrs() */
8260                         tbinfo->inhNotNull[j] = false;
8261                 }
8262
8263                 PQclear(res);
8264
8265                 /*
8266                  * Get info about column defaults
8267                  */
8268                 if (hasdefaults)
8269                 {
8270                         AttrDefInfo *attrdefs;
8271                         int                     numDefaults;
8272
8273                         if (g_verbose)
8274                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8275                                                   tbinfo->dobj.namespace->dobj.name,
8276                                                   tbinfo->dobj.name);
8277
8278                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8279                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8280                                                           "FROM pg_catalog.pg_attrdef "
8281                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8282                                                           tbinfo->dobj.catId.oid);
8283
8284                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8285
8286                         numDefaults = PQntuples(res);
8287                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8288
8289                         for (j = 0; j < numDefaults; j++)
8290                         {
8291                                 int                     adnum;
8292
8293                                 adnum = atoi(PQgetvalue(res, j, 2));
8294
8295                                 if (adnum <= 0 || adnum > ntups)
8296                                         exit_horribly(NULL,
8297                                                                   "invalid adnum value %d for table \"%s\"\n",
8298                                                                   adnum, tbinfo->dobj.name);
8299
8300                                 /*
8301                                  * dropped columns shouldn't have defaults, but just in case,
8302                                  * ignore 'em
8303                                  */
8304                                 if (tbinfo->attisdropped[adnum - 1])
8305                                         continue;
8306
8307                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8308                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8309                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8310                                 AssignDumpId(&attrdefs[j].dobj);
8311                                 attrdefs[j].adtable = tbinfo;
8312                                 attrdefs[j].adnum = adnum;
8313                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8314
8315                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8316                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8317
8318                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8319
8320                                 /*
8321                                  * Defaults on a VIEW must always be dumped as separate ALTER
8322                                  * TABLE commands.  Defaults on regular tables are dumped as
8323                                  * part of the CREATE TABLE if possible, which it won't be if
8324                                  * the column is not going to be emitted explicitly.
8325                                  */
8326                                 if (tbinfo->relkind == RELKIND_VIEW)
8327                                 {
8328                                         attrdefs[j].separate = true;
8329                                 }
8330                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8331                                 {
8332                                         /* column will be suppressed, print default separately */
8333                                         attrdefs[j].separate = true;
8334                                 }
8335                                 else
8336                                 {
8337                                         attrdefs[j].separate = false;
8338
8339                                         /*
8340                                          * Mark the default as needing to appear before the table,
8341                                          * so that any dependencies it has must be emitted before
8342                                          * the CREATE TABLE.  If this is not possible, we'll
8343                                          * change to "separate" mode while sorting dependencies.
8344                                          */
8345                                         addObjectDependency(&tbinfo->dobj,
8346                                                                                 attrdefs[j].dobj.dumpId);
8347                                 }
8348
8349                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8350                         }
8351                         PQclear(res);
8352                 }
8353
8354                 /*
8355                  * Get info about table CHECK constraints
8356                  */
8357                 if (tbinfo->ncheck > 0)
8358                 {
8359                         ConstraintInfo *constrs;
8360                         int                     numConstrs;
8361
8362                         if (g_verbose)
8363                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8364                                                   tbinfo->dobj.namespace->dobj.name,
8365                                                   tbinfo->dobj.name);
8366
8367                         resetPQExpBuffer(q);
8368                         if (fout->remoteVersion >= 90200)
8369                         {
8370                                 /*
8371                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8372                                  * but it wasn't ever false for check constraints until 9.2).
8373                                  */
8374                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8375                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8376                                                                   "conislocal, convalidated "
8377                                                                   "FROM pg_catalog.pg_constraint "
8378                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8379                                                                   "   AND contype = 'c' "
8380                                                                   "ORDER BY conname",
8381                                                                   tbinfo->dobj.catId.oid);
8382                         }
8383                         else if (fout->remoteVersion >= 80400)
8384                         {
8385                                 /* conislocal is new in 8.4 */
8386                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8387                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8388                                                                   "conislocal, true AS convalidated "
8389                                                                   "FROM pg_catalog.pg_constraint "
8390                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8391                                                                   "   AND contype = 'c' "
8392                                                                   "ORDER BY conname",
8393                                                                   tbinfo->dobj.catId.oid);
8394                         }
8395                         else
8396                         {
8397                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8398                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8399                                                                   "true AS conislocal, true AS convalidated "
8400                                                                   "FROM pg_catalog.pg_constraint "
8401                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8402                                                                   "   AND contype = 'c' "
8403                                                                   "ORDER BY conname",
8404                                                                   tbinfo->dobj.catId.oid);
8405                         }
8406
8407                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8408
8409                         numConstrs = PQntuples(res);
8410                         if (numConstrs != tbinfo->ncheck)
8411                         {
8412                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8413                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8414                                                                                  tbinfo->ncheck),
8415                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8416                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8417                                 exit_nicely(1);
8418                         }
8419
8420                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8421                         tbinfo->checkexprs = constrs;
8422
8423                         for (j = 0; j < numConstrs; j++)
8424                         {
8425                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8426
8427                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8428                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8429                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8430                                 AssignDumpId(&constrs[j].dobj);
8431                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8432                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8433                                 constrs[j].contable = tbinfo;
8434                                 constrs[j].condomain = NULL;
8435                                 constrs[j].contype = 'c';
8436                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8437                                 constrs[j].confrelid = InvalidOid;
8438                                 constrs[j].conindex = 0;
8439                                 constrs[j].condeferrable = false;
8440                                 constrs[j].condeferred = false;
8441                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8442
8443                                 /*
8444                                  * An unvalidated constraint needs to be dumped separately, so
8445                                  * that potentially-violating existing data is loaded before
8446                                  * the constraint.
8447                                  */
8448                                 constrs[j].separate = !validated;
8449
8450                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8451
8452                                 /*
8453                                  * Mark the constraint as needing to appear before the table
8454                                  * --- this is so that any other dependencies of the
8455                                  * constraint will be emitted before we try to create the
8456                                  * table.  If the constraint is to be dumped separately, it
8457                                  * will be dumped after data is loaded anyway, so don't do it.
8458                                  * (There's an automatic dependency in the opposite direction
8459                                  * anyway, so don't need to add one manually here.)
8460                                  */
8461                                 if (!constrs[j].separate)
8462                                         addObjectDependency(&tbinfo->dobj,
8463                                                                                 constrs[j].dobj.dumpId);
8464
8465                                 /*
8466                                  * If the constraint is inherited, this will be detected later
8467                                  * (in pre-8.4 databases).  We also detect later if the
8468                                  * constraint must be split out from the table definition.
8469                                  */
8470                         }
8471                         PQclear(res);
8472                 }
8473         }
8474
8475         destroyPQExpBuffer(q);
8476 }
8477
8478 /*
8479  * Test whether a column should be printed as part of table's CREATE TABLE.
8480  * Column number is zero-based.
8481  *
8482  * Normally this is always true, but it's false for dropped columns, as well
8483  * as those that were inherited without any local definition.  (If we print
8484  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8485  * However, in binary_upgrade mode, we must print all such columns anyway and
8486  * fix the attislocal/attisdropped state later, so as to keep control of the
8487  * physical column order.
8488  *
8489  * This function exists because there are scattered nonobvious places that
8490  * must be kept in sync with this decision.
8491  */
8492 bool
8493 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8494 {
8495         if (dopt->binary_upgrade)
8496                 return true;
8497         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8498 }
8499
8500
8501 /*
8502  * getTSParsers:
8503  *        read all text search parsers in the system catalogs and return them
8504  *        in the TSParserInfo* structure
8505  *
8506  *      numTSParsers is set to the number of parsers read in
8507  */
8508 TSParserInfo *
8509 getTSParsers(Archive *fout, int *numTSParsers)
8510 {
8511         PGresult   *res;
8512         int                     ntups;
8513         int                     i;
8514         PQExpBuffer query;
8515         TSParserInfo *prsinfo;
8516         int                     i_tableoid;
8517         int                     i_oid;
8518         int                     i_prsname;
8519         int                     i_prsnamespace;
8520         int                     i_prsstart;
8521         int                     i_prstoken;
8522         int                     i_prsend;
8523         int                     i_prsheadline;
8524         int                     i_prslextype;
8525
8526         /* Before 8.3, there is no built-in text search support */
8527         if (fout->remoteVersion < 80300)
8528         {
8529                 *numTSParsers = 0;
8530                 return NULL;
8531         }
8532
8533         query = createPQExpBuffer();
8534
8535         /*
8536          * find all text search objects, including builtin ones; we filter out
8537          * system-defined objects at dump-out time.
8538          */
8539
8540         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8541                                                  "prsstart::oid, prstoken::oid, "
8542                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8543                                                  "FROM pg_ts_parser");
8544
8545         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8546
8547         ntups = PQntuples(res);
8548         *numTSParsers = ntups;
8549
8550         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8551
8552         i_tableoid = PQfnumber(res, "tableoid");
8553         i_oid = PQfnumber(res, "oid");
8554         i_prsname = PQfnumber(res, "prsname");
8555         i_prsnamespace = PQfnumber(res, "prsnamespace");
8556         i_prsstart = PQfnumber(res, "prsstart");
8557         i_prstoken = PQfnumber(res, "prstoken");
8558         i_prsend = PQfnumber(res, "prsend");
8559         i_prsheadline = PQfnumber(res, "prsheadline");
8560         i_prslextype = PQfnumber(res, "prslextype");
8561
8562         for (i = 0; i < ntups; i++)
8563         {
8564                 prsinfo[i].dobj.objType = DO_TSPARSER;
8565                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8566                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8567                 AssignDumpId(&prsinfo[i].dobj);
8568                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8569                 prsinfo[i].dobj.namespace =
8570                         findNamespace(fout,
8571                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8572                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8573                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8574                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8575                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8576                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8577
8578                 /* Decide whether we want to dump it */
8579                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8580
8581                 /* Text Search Parsers do not currently have ACLs. */
8582                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8583         }
8584
8585         PQclear(res);
8586
8587         destroyPQExpBuffer(query);
8588
8589         return prsinfo;
8590 }
8591
8592 /*
8593  * getTSDictionaries:
8594  *        read all text search dictionaries in the system catalogs and return them
8595  *        in the TSDictInfo* structure
8596  *
8597  *      numTSDicts is set to the number of dictionaries read in
8598  */
8599 TSDictInfo *
8600 getTSDictionaries(Archive *fout, int *numTSDicts)
8601 {
8602         PGresult   *res;
8603         int                     ntups;
8604         int                     i;
8605         PQExpBuffer query;
8606         TSDictInfo *dictinfo;
8607         int                     i_tableoid;
8608         int                     i_oid;
8609         int                     i_dictname;
8610         int                     i_dictnamespace;
8611         int                     i_rolname;
8612         int                     i_dicttemplate;
8613         int                     i_dictinitoption;
8614
8615         /* Before 8.3, there is no built-in text search support */
8616         if (fout->remoteVersion < 80300)
8617         {
8618                 *numTSDicts = 0;
8619                 return NULL;
8620         }
8621
8622         query = createPQExpBuffer();
8623
8624         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8625                                           "dictnamespace, (%s dictowner) AS rolname, "
8626                                           "dicttemplate, dictinitoption "
8627                                           "FROM pg_ts_dict",
8628                                           username_subquery);
8629
8630         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8631
8632         ntups = PQntuples(res);
8633         *numTSDicts = ntups;
8634
8635         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8636
8637         i_tableoid = PQfnumber(res, "tableoid");
8638         i_oid = PQfnumber(res, "oid");
8639         i_dictname = PQfnumber(res, "dictname");
8640         i_dictnamespace = PQfnumber(res, "dictnamespace");
8641         i_rolname = PQfnumber(res, "rolname");
8642         i_dictinitoption = PQfnumber(res, "dictinitoption");
8643         i_dicttemplate = PQfnumber(res, "dicttemplate");
8644
8645         for (i = 0; i < ntups; i++)
8646         {
8647                 dictinfo[i].dobj.objType = DO_TSDICT;
8648                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8649                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8650                 AssignDumpId(&dictinfo[i].dobj);
8651                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8652                 dictinfo[i].dobj.namespace =
8653                         findNamespace(fout,
8654                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8655                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8656                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8657                 if (PQgetisnull(res, i, i_dictinitoption))
8658                         dictinfo[i].dictinitoption = NULL;
8659                 else
8660                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8661
8662                 /* Decide whether we want to dump it */
8663                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8664
8665                 /* Text Search Dictionaries do not currently have ACLs. */
8666                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8667         }
8668
8669         PQclear(res);
8670
8671         destroyPQExpBuffer(query);
8672
8673         return dictinfo;
8674 }
8675
8676 /*
8677  * getTSTemplates:
8678  *        read all text search templates in the system catalogs and return them
8679  *        in the TSTemplateInfo* structure
8680  *
8681  *      numTSTemplates is set to the number of templates read in
8682  */
8683 TSTemplateInfo *
8684 getTSTemplates(Archive *fout, int *numTSTemplates)
8685 {
8686         PGresult   *res;
8687         int                     ntups;
8688         int                     i;
8689         PQExpBuffer query;
8690         TSTemplateInfo *tmplinfo;
8691         int                     i_tableoid;
8692         int                     i_oid;
8693         int                     i_tmplname;
8694         int                     i_tmplnamespace;
8695         int                     i_tmplinit;
8696         int                     i_tmpllexize;
8697
8698         /* Before 8.3, there is no built-in text search support */
8699         if (fout->remoteVersion < 80300)
8700         {
8701                 *numTSTemplates = 0;
8702                 return NULL;
8703         }
8704
8705         query = createPQExpBuffer();
8706
8707         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8708                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8709                                                  "FROM pg_ts_template");
8710
8711         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8712
8713         ntups = PQntuples(res);
8714         *numTSTemplates = ntups;
8715
8716         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8717
8718         i_tableoid = PQfnumber(res, "tableoid");
8719         i_oid = PQfnumber(res, "oid");
8720         i_tmplname = PQfnumber(res, "tmplname");
8721         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8722         i_tmplinit = PQfnumber(res, "tmplinit");
8723         i_tmpllexize = PQfnumber(res, "tmpllexize");
8724
8725         for (i = 0; i < ntups; i++)
8726         {
8727                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8728                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8729                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8730                 AssignDumpId(&tmplinfo[i].dobj);
8731                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8732                 tmplinfo[i].dobj.namespace =
8733                         findNamespace(fout,
8734                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8735                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8736                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8737
8738                 /* Decide whether we want to dump it */
8739                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8740
8741                 /* Text Search Templates do not currently have ACLs. */
8742                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8743         }
8744
8745         PQclear(res);
8746
8747         destroyPQExpBuffer(query);
8748
8749         return tmplinfo;
8750 }
8751
8752 /*
8753  * getTSConfigurations:
8754  *        read all text search configurations in the system catalogs and return
8755  *        them in the TSConfigInfo* structure
8756  *
8757  *      numTSConfigs is set to the number of configurations read in
8758  */
8759 TSConfigInfo *
8760 getTSConfigurations(Archive *fout, int *numTSConfigs)
8761 {
8762         PGresult   *res;
8763         int                     ntups;
8764         int                     i;
8765         PQExpBuffer query;
8766         TSConfigInfo *cfginfo;
8767         int                     i_tableoid;
8768         int                     i_oid;
8769         int                     i_cfgname;
8770         int                     i_cfgnamespace;
8771         int                     i_rolname;
8772         int                     i_cfgparser;
8773
8774         /* Before 8.3, there is no built-in text search support */
8775         if (fout->remoteVersion < 80300)
8776         {
8777                 *numTSConfigs = 0;
8778                 return NULL;
8779         }
8780
8781         query = createPQExpBuffer();
8782
8783         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8784                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8785                                           "FROM pg_ts_config",
8786                                           username_subquery);
8787
8788         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8789
8790         ntups = PQntuples(res);
8791         *numTSConfigs = ntups;
8792
8793         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8794
8795         i_tableoid = PQfnumber(res, "tableoid");
8796         i_oid = PQfnumber(res, "oid");
8797         i_cfgname = PQfnumber(res, "cfgname");
8798         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8799         i_rolname = PQfnumber(res, "rolname");
8800         i_cfgparser = PQfnumber(res, "cfgparser");
8801
8802         for (i = 0; i < ntups; i++)
8803         {
8804                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8805                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8806                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8807                 AssignDumpId(&cfginfo[i].dobj);
8808                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8809                 cfginfo[i].dobj.namespace =
8810                         findNamespace(fout,
8811                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8812                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8813                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8814
8815                 /* Decide whether we want to dump it */
8816                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8817
8818                 /* Text Search Configurations do not currently have ACLs. */
8819                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8820         }
8821
8822         PQclear(res);
8823
8824         destroyPQExpBuffer(query);
8825
8826         return cfginfo;
8827 }
8828
8829 /*
8830  * getForeignDataWrappers:
8831  *        read all foreign-data wrappers in the system catalogs and return
8832  *        them in the FdwInfo* structure
8833  *
8834  *      numForeignDataWrappers is set to the number of fdws read in
8835  */
8836 FdwInfo *
8837 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8838 {
8839         DumpOptions *dopt = fout->dopt;
8840         PGresult   *res;
8841         int                     ntups;
8842         int                     i;
8843         PQExpBuffer query;
8844         FdwInfo    *fdwinfo;
8845         int                     i_tableoid;
8846         int                     i_oid;
8847         int                     i_fdwname;
8848         int                     i_rolname;
8849         int                     i_fdwhandler;
8850         int                     i_fdwvalidator;
8851         int                     i_fdwacl;
8852         int                     i_rfdwacl;
8853         int                     i_initfdwacl;
8854         int                     i_initrfdwacl;
8855         int                     i_fdwoptions;
8856
8857         /* Before 8.4, there are no foreign-data wrappers */
8858         if (fout->remoteVersion < 80400)
8859         {
8860                 *numForeignDataWrappers = 0;
8861                 return NULL;
8862         }
8863
8864         query = createPQExpBuffer();
8865
8866         if (fout->remoteVersion >= 90600)
8867         {
8868                 PQExpBuffer acl_subquery = createPQExpBuffer();
8869                 PQExpBuffer racl_subquery = createPQExpBuffer();
8870                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8871                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8872
8873                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8874                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8875                                                 dopt->binary_upgrade);
8876
8877                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8878                                                   "(%s f.fdwowner) AS rolname, "
8879                                                   "f.fdwhandler::pg_catalog.regproc, "
8880                                                   "f.fdwvalidator::pg_catalog.regproc, "
8881                                                   "%s AS fdwacl, "
8882                                                   "%s AS rfdwacl, "
8883                                                   "%s AS initfdwacl, "
8884                                                   "%s AS initrfdwacl, "
8885                                                   "array_to_string(ARRAY("
8886                                                   "SELECT quote_ident(option_name) || ' ' || "
8887                                                   "quote_literal(option_value) "
8888                                                   "FROM pg_options_to_table(f.fdwoptions) "
8889                                                   "ORDER BY option_name"
8890                                                   "), E',\n    ') AS fdwoptions "
8891                                                   "FROM pg_foreign_data_wrapper f "
8892                                                   "LEFT JOIN pg_init_privs pip ON "
8893                                                   "(f.oid = pip.objoid "
8894                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8895                                                   "AND pip.objsubid = 0) ",
8896                                                   username_subquery,
8897                                                   acl_subquery->data,
8898                                                   racl_subquery->data,
8899                                                   initacl_subquery->data,
8900                                                   initracl_subquery->data);
8901
8902                 destroyPQExpBuffer(acl_subquery);
8903                 destroyPQExpBuffer(racl_subquery);
8904                 destroyPQExpBuffer(initacl_subquery);
8905                 destroyPQExpBuffer(initracl_subquery);
8906         }
8907         else if (fout->remoteVersion >= 90100)
8908         {
8909                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8910                                                   "(%s fdwowner) AS rolname, "
8911                                                   "fdwhandler::pg_catalog.regproc, "
8912                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8913                                                   "NULL as rfdwacl, "
8914                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8915                                                   "array_to_string(ARRAY("
8916                                                   "SELECT quote_ident(option_name) || ' ' || "
8917                                                   "quote_literal(option_value) "
8918                                                   "FROM pg_options_to_table(fdwoptions) "
8919                                                   "ORDER BY option_name"
8920                                                   "), E',\n    ') AS fdwoptions "
8921                                                   "FROM pg_foreign_data_wrapper",
8922                                                   username_subquery);
8923         }
8924         else
8925         {
8926                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8927                                                   "(%s fdwowner) AS rolname, "
8928                                                   "'-' AS fdwhandler, "
8929                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8930                                                   "NULL as rfdwacl, "
8931                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8932                                                   "array_to_string(ARRAY("
8933                                                   "SELECT quote_ident(option_name) || ' ' || "
8934                                                   "quote_literal(option_value) "
8935                                                   "FROM pg_options_to_table(fdwoptions) "
8936                                                   "ORDER BY option_name"
8937                                                   "), E',\n    ') AS fdwoptions "
8938                                                   "FROM pg_foreign_data_wrapper",
8939                                                   username_subquery);
8940         }
8941
8942         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8943
8944         ntups = PQntuples(res);
8945         *numForeignDataWrappers = ntups;
8946
8947         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
8948
8949         i_tableoid = PQfnumber(res, "tableoid");
8950         i_oid = PQfnumber(res, "oid");
8951         i_fdwname = PQfnumber(res, "fdwname");
8952         i_rolname = PQfnumber(res, "rolname");
8953         i_fdwhandler = PQfnumber(res, "fdwhandler");
8954         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
8955         i_fdwacl = PQfnumber(res, "fdwacl");
8956         i_rfdwacl = PQfnumber(res, "rfdwacl");
8957         i_initfdwacl = PQfnumber(res, "initfdwacl");
8958         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
8959         i_fdwoptions = PQfnumber(res, "fdwoptions");
8960
8961         for (i = 0; i < ntups; i++)
8962         {
8963                 fdwinfo[i].dobj.objType = DO_FDW;
8964                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8965                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8966                 AssignDumpId(&fdwinfo[i].dobj);
8967                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
8968                 fdwinfo[i].dobj.namespace = NULL;
8969                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8970                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
8971                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
8972                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
8973                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
8974                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
8975                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
8976                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
8977
8978                 /* Decide whether we want to dump it */
8979                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
8980
8981                 /* Do not try to dump ACL if no ACL exists. */
8982                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
8983                         PQgetisnull(res, i, i_initfdwacl) &&
8984                         PQgetisnull(res, i, i_initrfdwacl))
8985                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8986         }
8987
8988         PQclear(res);
8989
8990         destroyPQExpBuffer(query);
8991
8992         return fdwinfo;
8993 }
8994
8995 /*
8996  * getForeignServers:
8997  *        read all foreign servers in the system catalogs and return
8998  *        them in the ForeignServerInfo * structure
8999  *
9000  *      numForeignServers is set to the number of servers read in
9001  */
9002 ForeignServerInfo *
9003 getForeignServers(Archive *fout, int *numForeignServers)
9004 {
9005         DumpOptions *dopt = fout->dopt;
9006         PGresult   *res;
9007         int                     ntups;
9008         int                     i;
9009         PQExpBuffer query;
9010         ForeignServerInfo *srvinfo;
9011         int                     i_tableoid;
9012         int                     i_oid;
9013         int                     i_srvname;
9014         int                     i_rolname;
9015         int                     i_srvfdw;
9016         int                     i_srvtype;
9017         int                     i_srvversion;
9018         int                     i_srvacl;
9019         int                     i_rsrvacl;
9020         int                     i_initsrvacl;
9021         int                     i_initrsrvacl;
9022         int                     i_srvoptions;
9023
9024         /* Before 8.4, there are no foreign servers */
9025         if (fout->remoteVersion < 80400)
9026         {
9027                 *numForeignServers = 0;
9028                 return NULL;
9029         }
9030
9031         query = createPQExpBuffer();
9032
9033         if (fout->remoteVersion >= 90600)
9034         {
9035                 PQExpBuffer acl_subquery = createPQExpBuffer();
9036                 PQExpBuffer racl_subquery = createPQExpBuffer();
9037                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9038                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9039
9040                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9041                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9042                                                 dopt->binary_upgrade);
9043
9044                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9045                                                   "(%s f.srvowner) AS rolname, "
9046                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9047                                                   "%s AS srvacl, "
9048                                                   "%s AS rsrvacl, "
9049                                                   "%s AS initsrvacl, "
9050                                                   "%s AS initrsrvacl, "
9051                                                   "array_to_string(ARRAY("
9052                                                   "SELECT quote_ident(option_name) || ' ' || "
9053                                                   "quote_literal(option_value) "
9054                                                   "FROM pg_options_to_table(f.srvoptions) "
9055                                                   "ORDER BY option_name"
9056                                                   "), E',\n    ') AS srvoptions "
9057                                                   "FROM pg_foreign_server f "
9058                                                   "LEFT JOIN pg_init_privs pip "
9059                                                   "ON (f.oid = pip.objoid "
9060                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9061                                                   "AND pip.objsubid = 0) ",
9062                                                   username_subquery,
9063                                                   acl_subquery->data,
9064                                                   racl_subquery->data,
9065                                                   initacl_subquery->data,
9066                                                   initracl_subquery->data);
9067
9068                 destroyPQExpBuffer(acl_subquery);
9069                 destroyPQExpBuffer(racl_subquery);
9070                 destroyPQExpBuffer(initacl_subquery);
9071                 destroyPQExpBuffer(initracl_subquery);
9072         }
9073         else
9074         {
9075                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9076                                                   "(%s srvowner) AS rolname, "
9077                                                   "srvfdw, srvtype, srvversion, srvacl, "
9078                                                   "NULL AS rsrvacl, "
9079                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9080                                                   "array_to_string(ARRAY("
9081                                                   "SELECT quote_ident(option_name) || ' ' || "
9082                                                   "quote_literal(option_value) "
9083                                                   "FROM pg_options_to_table(srvoptions) "
9084                                                   "ORDER BY option_name"
9085                                                   "), E',\n    ') AS srvoptions "
9086                                                   "FROM pg_foreign_server",
9087                                                   username_subquery);
9088         }
9089
9090         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9091
9092         ntups = PQntuples(res);
9093         *numForeignServers = ntups;
9094
9095         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9096
9097         i_tableoid = PQfnumber(res, "tableoid");
9098         i_oid = PQfnumber(res, "oid");
9099         i_srvname = PQfnumber(res, "srvname");
9100         i_rolname = PQfnumber(res, "rolname");
9101         i_srvfdw = PQfnumber(res, "srvfdw");
9102         i_srvtype = PQfnumber(res, "srvtype");
9103         i_srvversion = PQfnumber(res, "srvversion");
9104         i_srvacl = PQfnumber(res, "srvacl");
9105         i_rsrvacl = PQfnumber(res, "rsrvacl");
9106         i_initsrvacl = PQfnumber(res, "initsrvacl");
9107         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9108         i_srvoptions = PQfnumber(res, "srvoptions");
9109
9110         for (i = 0; i < ntups; i++)
9111         {
9112                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9113                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9114                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9115                 AssignDumpId(&srvinfo[i].dobj);
9116                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9117                 srvinfo[i].dobj.namespace = NULL;
9118                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9119                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9120                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9121                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9122                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9123                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9124                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9125                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9126                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9127
9128                 /* Decide whether we want to dump it */
9129                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9130
9131                 /* Do not try to dump ACL if no ACL exists. */
9132                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9133                         PQgetisnull(res, i, i_initsrvacl) &&
9134                         PQgetisnull(res, i, i_initrsrvacl))
9135                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9136         }
9137
9138         PQclear(res);
9139
9140         destroyPQExpBuffer(query);
9141
9142         return srvinfo;
9143 }
9144
9145 /*
9146  * getDefaultACLs:
9147  *        read all default ACL information in the system catalogs and return
9148  *        them in the DefaultACLInfo structure
9149  *
9150  *      numDefaultACLs is set to the number of ACLs read in
9151  */
9152 DefaultACLInfo *
9153 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9154 {
9155         DumpOptions *dopt = fout->dopt;
9156         DefaultACLInfo *daclinfo;
9157         PQExpBuffer query;
9158         PGresult   *res;
9159         int                     i_oid;
9160         int                     i_tableoid;
9161         int                     i_defaclrole;
9162         int                     i_defaclnamespace;
9163         int                     i_defaclobjtype;
9164         int                     i_defaclacl;
9165         int                     i_rdefaclacl;
9166         int                     i_initdefaclacl;
9167         int                     i_initrdefaclacl;
9168         int                     i,
9169                                 ntups;
9170
9171         if (fout->remoteVersion < 90000)
9172         {
9173                 *numDefaultACLs = 0;
9174                 return NULL;
9175         }
9176
9177         query = createPQExpBuffer();
9178
9179         if (fout->remoteVersion >= 90600)
9180         {
9181                 PQExpBuffer acl_subquery = createPQExpBuffer();
9182                 PQExpBuffer racl_subquery = createPQExpBuffer();
9183                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9184                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9185
9186                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9187                                                 initracl_subquery, "defaclacl", "defaclrole",
9188                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9189                                                 dopt->binary_upgrade);
9190
9191                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9192                                                   "(%s d.defaclrole) AS defaclrole, "
9193                                                   "d.defaclnamespace, "
9194                                                   "d.defaclobjtype, "
9195                                                   "%s AS defaclacl, "
9196                                                   "%s AS rdefaclacl, "
9197                                                   "%s AS initdefaclacl, "
9198                                                   "%s AS initrdefaclacl "
9199                                                   "FROM pg_default_acl d "
9200                                                   "LEFT JOIN pg_init_privs pip ON "
9201                                                   "(d.oid = pip.objoid "
9202                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9203                                                   "AND pip.objsubid = 0) ",
9204                                                   username_subquery,
9205                                                   acl_subquery->data,
9206                                                   racl_subquery->data,
9207                                                   initacl_subquery->data,
9208                                                   initracl_subquery->data);
9209         }
9210         else
9211         {
9212                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9213                                                   "(%s defaclrole) AS defaclrole, "
9214                                                   "defaclnamespace, "
9215                                                   "defaclobjtype, "
9216                                                   "defaclacl, "
9217                                                   "NULL AS rdefaclacl, "
9218                                                   "NULL AS initdefaclacl, "
9219                                                   "NULL AS initrdefaclacl "
9220                                                   "FROM pg_default_acl",
9221                                                   username_subquery);
9222         }
9223
9224         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9225
9226         ntups = PQntuples(res);
9227         *numDefaultACLs = ntups;
9228
9229         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9230
9231         i_oid = PQfnumber(res, "oid");
9232         i_tableoid = PQfnumber(res, "tableoid");
9233         i_defaclrole = PQfnumber(res, "defaclrole");
9234         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9235         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9236         i_defaclacl = PQfnumber(res, "defaclacl");
9237         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9238         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9239         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9240
9241         for (i = 0; i < ntups; i++)
9242         {
9243                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9244
9245                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9246                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9247                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9248                 AssignDumpId(&daclinfo[i].dobj);
9249                 /* cheesy ... is it worth coming up with a better object name? */
9250                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9251
9252                 if (nspid != InvalidOid)
9253                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9254                 else
9255                         daclinfo[i].dobj.namespace = NULL;
9256
9257                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9258                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9259                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9260                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9261                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9262                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9263
9264                 /* Decide whether we want to dump it */
9265                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9266         }
9267
9268         PQclear(res);
9269
9270         destroyPQExpBuffer(query);
9271
9272         return daclinfo;
9273 }
9274
9275 /*
9276  * dumpComment --
9277  *
9278  * This routine is used to dump any comments associated with the
9279  * object handed to this routine. The routine takes the object type
9280  * and object name (ready to print, except for schema decoration), plus
9281  * the namespace and owner of the object (for labeling the ArchiveEntry),
9282  * plus catalog ID and subid which are the lookup key for pg_description,
9283  * plus the dump ID for the object (for setting a dependency).
9284  * If a matching pg_description entry is found, it is dumped.
9285  *
9286  * Note: in some cases, such as comments for triggers and rules, the "type"
9287  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9288  * but it doesn't seem worth complicating the API for all callers to make
9289  * it cleaner.
9290  *
9291  * Note: although this routine takes a dumpId for dependency purposes,
9292  * that purpose is just to mark the dependency in the emitted dump file
9293  * for possible future use by pg_restore.  We do NOT use it for determining
9294  * ordering of the comment in the dump file, because this routine is called
9295  * after dependency sorting occurs.  This routine should be called just after
9296  * calling ArchiveEntry() for the specified object.
9297  */
9298 static void
9299 dumpComment(Archive *fout, const char *type, const char *name,
9300                         const char *namespace, const char *owner,
9301                         CatalogId catalogId, int subid, DumpId dumpId)
9302 {
9303         DumpOptions *dopt = fout->dopt;
9304         CommentItem *comments;
9305         int                     ncomments;
9306
9307         /* do nothing, if --no-comments is supplied */
9308         if (dopt->no_comments)
9309                 return;
9310
9311         /* Comments are schema not data ... except blob comments are data */
9312         if (strcmp(type, "LARGE OBJECT") != 0)
9313         {
9314                 if (dopt->dataOnly)
9315                         return;
9316         }
9317         else
9318         {
9319                 /* We do dump blob comments in binary-upgrade mode */
9320                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9321                         return;
9322         }
9323
9324         /* Search for comments associated with catalogId, using table */
9325         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9326                                                          &comments);
9327
9328         /* Is there one matching the subid? */
9329         while (ncomments > 0)
9330         {
9331                 if (comments->objsubid == subid)
9332                         break;
9333                 comments++;
9334                 ncomments--;
9335         }
9336
9337         /* If a comment exists, build COMMENT ON statement */
9338         if (ncomments > 0)
9339         {
9340                 PQExpBuffer query = createPQExpBuffer();
9341                 PQExpBuffer tag = createPQExpBuffer();
9342
9343                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9344                 if (namespace && *namespace)
9345                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9346                 appendPQExpBuffer(query, "%s IS ", name);
9347                 appendStringLiteralAH(query, comments->descr, fout);
9348                 appendPQExpBufferStr(query, ";\n");
9349
9350                 appendPQExpBuffer(tag, "%s %s", type, name);
9351
9352                 /*
9353                  * We mark comments as SECTION_NONE because they really belong in the
9354                  * same section as their parent, whether that is pre-data or
9355                  * post-data.
9356                  */
9357                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9358                                          tag->data, namespace, NULL, owner,
9359                                          "COMMENT", SECTION_NONE,
9360                                          query->data, "", NULL,
9361                                          &(dumpId), 1,
9362                                          NULL, NULL);
9363
9364                 destroyPQExpBuffer(query);
9365                 destroyPQExpBuffer(tag);
9366         }
9367 }
9368
9369 /*
9370  * dumpTableComment --
9371  *
9372  * As above, but dump comments for both the specified table (or view)
9373  * and its columns.
9374  */
9375 static void
9376 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9377                                  const char *reltypename)
9378 {
9379         DumpOptions *dopt = fout->dopt;
9380         CommentItem *comments;
9381         int                     ncomments;
9382         PQExpBuffer query;
9383         PQExpBuffer tag;
9384
9385         /* do nothing, if --no-comments is supplied */
9386         if (dopt->no_comments)
9387                 return;
9388
9389         /* Comments are SCHEMA not data */
9390         if (dopt->dataOnly)
9391                 return;
9392
9393         /* Search for comments associated with relation, using table */
9394         ncomments = findComments(fout,
9395                                                          tbinfo->dobj.catId.tableoid,
9396                                                          tbinfo->dobj.catId.oid,
9397                                                          &comments);
9398
9399         /* If comments exist, build COMMENT ON statements */
9400         if (ncomments <= 0)
9401                 return;
9402
9403         query = createPQExpBuffer();
9404         tag = createPQExpBuffer();
9405
9406         while (ncomments > 0)
9407         {
9408                 const char *descr = comments->descr;
9409                 int                     objsubid = comments->objsubid;
9410
9411                 if (objsubid == 0)
9412                 {
9413                         resetPQExpBuffer(tag);
9414                         appendPQExpBuffer(tag, "%s %s", reltypename,
9415                                                           fmtId(tbinfo->dobj.name));
9416
9417                         resetPQExpBuffer(query);
9418                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9419                                                           fmtQualifiedDumpable(tbinfo));
9420                         appendStringLiteralAH(query, descr, fout);
9421                         appendPQExpBufferStr(query, ";\n");
9422
9423                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9424                                                  tag->data,
9425                                                  tbinfo->dobj.namespace->dobj.name,
9426                                                  NULL, tbinfo->rolname,
9427                                                  "COMMENT", SECTION_NONE,
9428                                                  query->data, "", NULL,
9429                                                  &(tbinfo->dobj.dumpId), 1,
9430                                                  NULL, NULL);
9431                 }
9432                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9433                 {
9434                         resetPQExpBuffer(tag);
9435                         appendPQExpBuffer(tag, "COLUMN %s.",
9436                                                           fmtId(tbinfo->dobj.name));
9437                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9438
9439                         resetPQExpBuffer(query);
9440                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9441                                                           fmtQualifiedDumpable(tbinfo));
9442                         appendPQExpBuffer(query, "%s IS ",
9443                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9444                         appendStringLiteralAH(query, descr, fout);
9445                         appendPQExpBufferStr(query, ";\n");
9446
9447                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9448                                                  tag->data,
9449                                                  tbinfo->dobj.namespace->dobj.name,
9450                                                  NULL, tbinfo->rolname,
9451                                                  "COMMENT", SECTION_NONE,
9452                                                  query->data, "", NULL,
9453                                                  &(tbinfo->dobj.dumpId), 1,
9454                                                  NULL, NULL);
9455                 }
9456
9457                 comments++;
9458                 ncomments--;
9459         }
9460
9461         destroyPQExpBuffer(query);
9462         destroyPQExpBuffer(tag);
9463 }
9464
9465 /*
9466  * findComments --
9467  *
9468  * Find the comment(s), if any, associated with the given object.  All the
9469  * objsubid values associated with the given classoid/objoid are found with
9470  * one search.
9471  */
9472 static int
9473 findComments(Archive *fout, Oid classoid, Oid objoid,
9474                          CommentItem **items)
9475 {
9476         /* static storage for table of comments */
9477         static CommentItem *comments = NULL;
9478         static int      ncomments = -1;
9479
9480         CommentItem *middle = NULL;
9481         CommentItem *low;
9482         CommentItem *high;
9483         int                     nmatch;
9484
9485         /* Get comments if we didn't already */
9486         if (ncomments < 0)
9487                 ncomments = collectComments(fout, &comments);
9488
9489         /*
9490          * Do binary search to find some item matching the object.
9491          */
9492         low = &comments[0];
9493         high = &comments[ncomments - 1];
9494         while (low <= high)
9495         {
9496                 middle = low + (high - low) / 2;
9497
9498                 if (classoid < middle->classoid)
9499                         high = middle - 1;
9500                 else if (classoid > middle->classoid)
9501                         low = middle + 1;
9502                 else if (objoid < middle->objoid)
9503                         high = middle - 1;
9504                 else if (objoid > middle->objoid)
9505                         low = middle + 1;
9506                 else
9507                         break;                          /* found a match */
9508         }
9509
9510         if (low > high)                         /* no matches */
9511         {
9512                 *items = NULL;
9513                 return 0;
9514         }
9515
9516         /*
9517          * Now determine how many items match the object.  The search loop
9518          * invariant still holds: only items between low and high inclusive could
9519          * match.
9520          */
9521         nmatch = 1;
9522         while (middle > low)
9523         {
9524                 if (classoid != middle[-1].classoid ||
9525                         objoid != middle[-1].objoid)
9526                         break;
9527                 middle--;
9528                 nmatch++;
9529         }
9530
9531         *items = middle;
9532
9533         middle += nmatch;
9534         while (middle <= high)
9535         {
9536                 if (classoid != middle->classoid ||
9537                         objoid != middle->objoid)
9538                         break;
9539                 middle++;
9540                 nmatch++;
9541         }
9542
9543         return nmatch;
9544 }
9545
9546 /*
9547  * collectComments --
9548  *
9549  * Construct a table of all comments available for database objects.
9550  * We used to do per-object queries for the comments, but it's much faster
9551  * to pull them all over at once, and on most databases the memory cost
9552  * isn't high.
9553  *
9554  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9555  */
9556 static int
9557 collectComments(Archive *fout, CommentItem **items)
9558 {
9559         PGresult   *res;
9560         PQExpBuffer query;
9561         int                     i_description;
9562         int                     i_classoid;
9563         int                     i_objoid;
9564         int                     i_objsubid;
9565         int                     ntups;
9566         int                     i;
9567         CommentItem *comments;
9568
9569         query = createPQExpBuffer();
9570
9571         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9572                                                  "FROM pg_catalog.pg_description "
9573                                                  "ORDER BY classoid, objoid, objsubid");
9574
9575         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9576
9577         /* Construct lookup table containing OIDs in numeric form */
9578
9579         i_description = PQfnumber(res, "description");
9580         i_classoid = PQfnumber(res, "classoid");
9581         i_objoid = PQfnumber(res, "objoid");
9582         i_objsubid = PQfnumber(res, "objsubid");
9583
9584         ntups = PQntuples(res);
9585
9586         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9587
9588         for (i = 0; i < ntups; i++)
9589         {
9590                 comments[i].descr = PQgetvalue(res, i, i_description);
9591                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9592                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9593                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9594         }
9595
9596         /* Do NOT free the PGresult since we are keeping pointers into it */
9597         destroyPQExpBuffer(query);
9598
9599         *items = comments;
9600         return ntups;
9601 }
9602
9603 /*
9604  * dumpDumpableObject
9605  *
9606  * This routine and its subsidiaries are responsible for creating
9607  * ArchiveEntries (TOC objects) for each object to be dumped.
9608  */
9609 static void
9610 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9611 {
9612         switch (dobj->objType)
9613         {
9614                 case DO_NAMESPACE:
9615                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9616                         break;
9617                 case DO_EXTENSION:
9618                         dumpExtension(fout, (ExtensionInfo *) dobj);
9619                         break;
9620                 case DO_TYPE:
9621                         dumpType(fout, (TypeInfo *) dobj);
9622                         break;
9623                 case DO_SHELL_TYPE:
9624                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9625                         break;
9626                 case DO_FUNC:
9627                         dumpFunc(fout, (FuncInfo *) dobj);
9628                         break;
9629                 case DO_AGG:
9630                         dumpAgg(fout, (AggInfo *) dobj);
9631                         break;
9632                 case DO_OPERATOR:
9633                         dumpOpr(fout, (OprInfo *) dobj);
9634                         break;
9635                 case DO_ACCESS_METHOD:
9636                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9637                         break;
9638                 case DO_OPCLASS:
9639                         dumpOpclass(fout, (OpclassInfo *) dobj);
9640                         break;
9641                 case DO_OPFAMILY:
9642                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9643                         break;
9644                 case DO_COLLATION:
9645                         dumpCollation(fout, (CollInfo *) dobj);
9646                         break;
9647                 case DO_CONVERSION:
9648                         dumpConversion(fout, (ConvInfo *) dobj);
9649                         break;
9650                 case DO_TABLE:
9651                         dumpTable(fout, (TableInfo *) dobj);
9652                         break;
9653                 case DO_ATTRDEF:
9654                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9655                         break;
9656                 case DO_INDEX:
9657                         dumpIndex(fout, (IndxInfo *) dobj);
9658                         break;
9659                 case DO_INDEX_ATTACH:
9660                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9661                         break;
9662                 case DO_STATSEXT:
9663                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9664                         break;
9665                 case DO_REFRESH_MATVIEW:
9666                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9667                         break;
9668                 case DO_RULE:
9669                         dumpRule(fout, (RuleInfo *) dobj);
9670                         break;
9671                 case DO_TRIGGER:
9672                         dumpTrigger(fout, (TriggerInfo *) dobj);
9673                         break;
9674                 case DO_EVENT_TRIGGER:
9675                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9676                         break;
9677                 case DO_CONSTRAINT:
9678                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9679                         break;
9680                 case DO_FK_CONSTRAINT:
9681                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9682                         break;
9683                 case DO_PROCLANG:
9684                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9685                         break;
9686                 case DO_CAST:
9687                         dumpCast(fout, (CastInfo *) dobj);
9688                         break;
9689                 case DO_TRANSFORM:
9690                         dumpTransform(fout, (TransformInfo *) dobj);
9691                         break;
9692                 case DO_SEQUENCE_SET:
9693                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9694                         break;
9695                 case DO_TABLE_DATA:
9696                         dumpTableData(fout, (TableDataInfo *) dobj);
9697                         break;
9698                 case DO_DUMMY_TYPE:
9699                         /* table rowtypes and array types are never dumped separately */
9700                         break;
9701                 case DO_TSPARSER:
9702                         dumpTSParser(fout, (TSParserInfo *) dobj);
9703                         break;
9704                 case DO_TSDICT:
9705                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9706                         break;
9707                 case DO_TSTEMPLATE:
9708                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9709                         break;
9710                 case DO_TSCONFIG:
9711                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9712                         break;
9713                 case DO_FDW:
9714                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9715                         break;
9716                 case DO_FOREIGN_SERVER:
9717                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9718                         break;
9719                 case DO_DEFAULT_ACL:
9720                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9721                         break;
9722                 case DO_BLOB:
9723                         dumpBlob(fout, (BlobInfo *) dobj);
9724                         break;
9725                 case DO_BLOB_DATA:
9726                         if (dobj->dump & DUMP_COMPONENT_DATA)
9727                         {
9728                                 TocEntry   *te;
9729
9730                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9731                                                                   dobj->name, NULL, NULL, "",
9732                                                                   "BLOBS", SECTION_DATA,
9733                                                                   "", "", NULL,
9734                                                                   NULL, 0,
9735                                                                   dumpBlobs, NULL);
9736
9737                                 /*
9738                                  * Set the TocEntry's dataLength in case we are doing a
9739                                  * parallel dump and want to order dump jobs by table size.
9740                                  * (We need some size estimate for every TocEntry with a
9741                                  * DataDumper function.)  We don't currently have any cheap
9742                                  * way to estimate the size of blobs, but it doesn't matter;
9743                                  * let's just set the size to a large value so parallel dumps
9744                                  * will launch this job first.  If there's lots of blobs, we
9745                                  * win, and if there aren't, we don't lose much.  (If you want
9746                                  * to improve on this, really what you should be thinking
9747                                  * about is allowing blob dumping to be parallelized, not just
9748                                  * getting a smarter estimate for the single TOC entry.)
9749                                  */
9750                                 te->dataLength = MaxBlockNumber;
9751                         }
9752                         break;
9753                 case DO_POLICY:
9754                         dumpPolicy(fout, (PolicyInfo *) dobj);
9755                         break;
9756                 case DO_PUBLICATION:
9757                         dumpPublication(fout, (PublicationInfo *) dobj);
9758                         break;
9759                 case DO_PUBLICATION_REL:
9760                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9761                         break;
9762                 case DO_SUBSCRIPTION:
9763                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9764                         break;
9765                 case DO_PRE_DATA_BOUNDARY:
9766                 case DO_POST_DATA_BOUNDARY:
9767                         /* never dumped, nothing to do */
9768                         break;
9769         }
9770 }
9771
9772 /*
9773  * dumpNamespace
9774  *        writes out to fout the queries to recreate a user-defined namespace
9775  */
9776 static void
9777 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9778 {
9779         DumpOptions *dopt = fout->dopt;
9780         PQExpBuffer q;
9781         PQExpBuffer delq;
9782         char       *qnspname;
9783
9784         /* Skip if not to be dumped */
9785         if (!nspinfo->dobj.dump || dopt->dataOnly)
9786                 return;
9787
9788         q = createPQExpBuffer();
9789         delq = createPQExpBuffer();
9790
9791         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9792
9793         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9794
9795         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9796
9797         if (dopt->binary_upgrade)
9798                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9799                                                                                 "SCHEMA", qnspname, NULL);
9800
9801         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9802                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9803                                          nspinfo->dobj.name,
9804                                          NULL, NULL,
9805                                          nspinfo->rolname,
9806                                          "SCHEMA", SECTION_PRE_DATA,
9807                                          q->data, delq->data, NULL,
9808                                          NULL, 0,
9809                                          NULL, NULL);
9810
9811         /* Dump Schema Comments and Security Labels */
9812         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9813                 dumpComment(fout, "SCHEMA", qnspname,
9814                                         NULL, nspinfo->rolname,
9815                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9816
9817         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9818                 dumpSecLabel(fout, "SCHEMA", qnspname,
9819                                          NULL, nspinfo->rolname,
9820                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9821
9822         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9823                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9824                                 qnspname, NULL, NULL,
9825                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9826                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9827
9828         free(qnspname);
9829
9830         destroyPQExpBuffer(q);
9831         destroyPQExpBuffer(delq);
9832 }
9833
9834 /*
9835  * dumpExtension
9836  *        writes out to fout the queries to recreate an extension
9837  */
9838 static void
9839 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9840 {
9841         DumpOptions *dopt = fout->dopt;
9842         PQExpBuffer q;
9843         PQExpBuffer delq;
9844         char       *qextname;
9845
9846         /* Skip if not to be dumped */
9847         if (!extinfo->dobj.dump || dopt->dataOnly)
9848                 return;
9849
9850         q = createPQExpBuffer();
9851         delq = createPQExpBuffer();
9852
9853         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9854
9855         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9856
9857         if (!dopt->binary_upgrade)
9858         {
9859                 /*
9860                  * In a regular dump, we simply create the extension, intentionally
9861                  * not specifying a version, so that the destination installation's
9862                  * default version is used.
9863                  *
9864                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9865                  * types; but there are various scenarios in which it's convenient to
9866                  * manually create the desired extension before restoring, so we
9867                  * prefer to allow it to exist already.
9868                  */
9869                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9870                                                   qextname, fmtId(extinfo->namespace));
9871         }
9872         else
9873         {
9874                 /*
9875                  * In binary-upgrade mode, it's critical to reproduce the state of the
9876                  * database exactly, so our procedure is to create an empty extension,
9877                  * restore all the contained objects normally, and add them to the
9878                  * extension one by one.  This function performs just the first of
9879                  * those steps.  binary_upgrade_extension_member() takes care of
9880                  * adding member objects as they're created.
9881                  */
9882                 int                     i;
9883                 int                     n;
9884
9885                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9886
9887                 /*
9888                  * We unconditionally create the extension, so we must drop it if it
9889                  * exists.  This could happen if the user deleted 'plpgsql' and then
9890                  * readded it, causing its oid to be greater than g_last_builtin_oid.
9891                  */
9892                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9893
9894                 appendPQExpBufferStr(q,
9895                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9896                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
9897                 appendPQExpBufferStr(q, ", ");
9898                 appendStringLiteralAH(q, extinfo->namespace, fout);
9899                 appendPQExpBufferStr(q, ", ");
9900                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9901                 appendStringLiteralAH(q, extinfo->extversion, fout);
9902                 appendPQExpBufferStr(q, ", ");
9903
9904                 /*
9905                  * Note that we're pushing extconfig (an OID array) back into
9906                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
9907                  * preserved in binary upgrade.
9908                  */
9909                 if (strlen(extinfo->extconfig) > 2)
9910                         appendStringLiteralAH(q, extinfo->extconfig, fout);
9911                 else
9912                         appendPQExpBufferStr(q, "NULL");
9913                 appendPQExpBufferStr(q, ", ");
9914                 if (strlen(extinfo->extcondition) > 2)
9915                         appendStringLiteralAH(q, extinfo->extcondition, fout);
9916                 else
9917                         appendPQExpBufferStr(q, "NULL");
9918                 appendPQExpBufferStr(q, ", ");
9919                 appendPQExpBufferStr(q, "ARRAY[");
9920                 n = 0;
9921                 for (i = 0; i < extinfo->dobj.nDeps; i++)
9922                 {
9923                         DumpableObject *extobj;
9924
9925                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9926                         if (extobj && extobj->objType == DO_EXTENSION)
9927                         {
9928                                 if (n++ > 0)
9929                                         appendPQExpBufferChar(q, ',');
9930                                 appendStringLiteralAH(q, extobj->name, fout);
9931                         }
9932                 }
9933                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9934                 appendPQExpBufferStr(q, ");\n");
9935         }
9936
9937         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9938                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9939                                          extinfo->dobj.name,
9940                                          NULL, NULL,
9941                                          "",
9942                                          "EXTENSION", SECTION_PRE_DATA,
9943                                          q->data, delq->data, NULL,
9944                                          NULL, 0,
9945                                          NULL, NULL);
9946
9947         /* Dump Extension Comments and Security Labels */
9948         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9949                 dumpComment(fout, "EXTENSION", qextname,
9950                                         NULL, "",
9951                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9952
9953         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9954                 dumpSecLabel(fout, "EXTENSION", qextname,
9955                                          NULL, "",
9956                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9957
9958         free(qextname);
9959
9960         destroyPQExpBuffer(q);
9961         destroyPQExpBuffer(delq);
9962 }
9963
9964 /*
9965  * dumpType
9966  *        writes out to fout the queries to recreate a user-defined type
9967  */
9968 static void
9969 dumpType(Archive *fout, TypeInfo *tyinfo)
9970 {
9971         DumpOptions *dopt = fout->dopt;
9972
9973         /* Skip if not to be dumped */
9974         if (!tyinfo->dobj.dump || dopt->dataOnly)
9975                 return;
9976
9977         /* Dump out in proper style */
9978         if (tyinfo->typtype == TYPTYPE_BASE)
9979                 dumpBaseType(fout, tyinfo);
9980         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
9981                 dumpDomain(fout, tyinfo);
9982         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
9983                 dumpCompositeType(fout, tyinfo);
9984         else if (tyinfo->typtype == TYPTYPE_ENUM)
9985                 dumpEnumType(fout, tyinfo);
9986         else if (tyinfo->typtype == TYPTYPE_RANGE)
9987                 dumpRangeType(fout, tyinfo);
9988         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
9989                 dumpUndefinedType(fout, tyinfo);
9990         else
9991                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
9992                                   tyinfo->dobj.name);
9993 }
9994
9995 /*
9996  * dumpEnumType
9997  *        writes out to fout the queries to recreate a user-defined enum type
9998  */
9999 static void
10000 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10001 {
10002         DumpOptions *dopt = fout->dopt;
10003         PQExpBuffer q = createPQExpBuffer();
10004         PQExpBuffer delq = createPQExpBuffer();
10005         PQExpBuffer query = createPQExpBuffer();
10006         PGresult   *res;
10007         int                     num,
10008                                 i;
10009         Oid                     enum_oid;
10010         char       *qtypname;
10011         char       *qualtypname;
10012         char       *label;
10013
10014         if (fout->remoteVersion >= 90100)
10015                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10016                                                   "FROM pg_catalog.pg_enum "
10017                                                   "WHERE enumtypid = '%u'"
10018                                                   "ORDER BY enumsortorder",
10019                                                   tyinfo->dobj.catId.oid);
10020         else
10021                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10022                                                   "FROM pg_catalog.pg_enum "
10023                                                   "WHERE enumtypid = '%u'"
10024                                                   "ORDER BY oid",
10025                                                   tyinfo->dobj.catId.oid);
10026
10027         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10028
10029         num = PQntuples(res);
10030
10031         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10032         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10033
10034         /*
10035          * CASCADE shouldn't be required here as for normal types since the I/O
10036          * functions are generic and do not get dropped.
10037          */
10038         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10039
10040         if (dopt->binary_upgrade)
10041                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10042                                                                                                  tyinfo->dobj.catId.oid,
10043                                                                                                  false);
10044
10045         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10046                                           qualtypname);
10047
10048         if (!dopt->binary_upgrade)
10049         {
10050                 /* Labels with server-assigned oids */
10051                 for (i = 0; i < num; i++)
10052                 {
10053                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10054                         if (i > 0)
10055                                 appendPQExpBufferChar(q, ',');
10056                         appendPQExpBufferStr(q, "\n    ");
10057                         appendStringLiteralAH(q, label, fout);
10058                 }
10059         }
10060
10061         appendPQExpBufferStr(q, "\n);\n");
10062
10063         if (dopt->binary_upgrade)
10064         {
10065                 /* Labels with dump-assigned (preserved) oids */
10066                 for (i = 0; i < num; i++)
10067                 {
10068                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10069                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10070
10071                         if (i == 0)
10072                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10073                         appendPQExpBuffer(q,
10074                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10075                                                           enum_oid);
10076                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10077                         appendStringLiteralAH(q, label, fout);
10078                         appendPQExpBufferStr(q, ";\n\n");
10079                 }
10080         }
10081
10082         if (dopt->binary_upgrade)
10083                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10084                                                                                 "TYPE", qtypname,
10085                                                                                 tyinfo->dobj.namespace->dobj.name);
10086
10087         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10088                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10089                                          tyinfo->dobj.name,
10090                                          tyinfo->dobj.namespace->dobj.name,
10091                                          NULL,
10092                                          tyinfo->rolname,
10093                                          "TYPE", SECTION_PRE_DATA,
10094                                          q->data, delq->data, NULL,
10095                                          NULL, 0,
10096                                          NULL, NULL);
10097
10098         /* Dump Type Comments and Security Labels */
10099         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10100                 dumpComment(fout, "TYPE", qtypname,
10101                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10102                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10103
10104         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10105                 dumpSecLabel(fout, "TYPE", qtypname,
10106                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10107                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10108
10109         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10110                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10111                                 qtypname, NULL,
10112                                 tyinfo->dobj.namespace->dobj.name,
10113                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10114                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10115
10116         PQclear(res);
10117         destroyPQExpBuffer(q);
10118         destroyPQExpBuffer(delq);
10119         destroyPQExpBuffer(query);
10120         free(qtypname);
10121         free(qualtypname);
10122 }
10123
10124 /*
10125  * dumpRangeType
10126  *        writes out to fout the queries to recreate a user-defined range type
10127  */
10128 static void
10129 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10130 {
10131         DumpOptions *dopt = fout->dopt;
10132         PQExpBuffer q = createPQExpBuffer();
10133         PQExpBuffer delq = createPQExpBuffer();
10134         PQExpBuffer query = createPQExpBuffer();
10135         PGresult   *res;
10136         Oid                     collationOid;
10137         char       *qtypname;
10138         char       *qualtypname;
10139         char       *procname;
10140
10141         appendPQExpBuffer(query,
10142                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10143                                           "opc.opcname AS opcname, "
10144                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10145                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10146                                           "opc.opcdefault, "
10147                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10148                                           "     ELSE rngcollation END AS collation, "
10149                                           "rngcanonical, rngsubdiff "
10150                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10151                                           "     pg_catalog.pg_opclass opc "
10152                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10153                                           "rngtypid = '%u'",
10154                                           tyinfo->dobj.catId.oid);
10155
10156         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10157
10158         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10159         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10160
10161         /*
10162          * CASCADE shouldn't be required here as for normal types since the I/O
10163          * functions are generic and do not get dropped.
10164          */
10165         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10166
10167         if (dopt->binary_upgrade)
10168                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10169                                                                                                  tyinfo->dobj.catId.oid,
10170                                                                                                  false);
10171
10172         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10173                                           qualtypname);
10174
10175         appendPQExpBuffer(q, "\n    subtype = %s",
10176                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10177
10178         /* print subtype_opclass only if not default for subtype */
10179         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10180         {
10181                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10182                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10183
10184                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10185                                                   fmtId(nspname));
10186                 appendPQExpBufferStr(q, fmtId(opcname));
10187         }
10188
10189         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10190         if (OidIsValid(collationOid))
10191         {
10192                 CollInfo   *coll = findCollationByOid(collationOid);
10193
10194                 if (coll)
10195                         appendPQExpBuffer(q, ",\n    collation = %s",
10196                                                           fmtQualifiedDumpable(coll));
10197         }
10198
10199         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10200         if (strcmp(procname, "-") != 0)
10201                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10202
10203         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10204         if (strcmp(procname, "-") != 0)
10205                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10206
10207         appendPQExpBufferStr(q, "\n);\n");
10208
10209         if (dopt->binary_upgrade)
10210                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10211                                                                                 "TYPE", qtypname,
10212                                                                                 tyinfo->dobj.namespace->dobj.name);
10213
10214         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10215                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10216                                          tyinfo->dobj.name,
10217                                          tyinfo->dobj.namespace->dobj.name,
10218                                          NULL,
10219                                          tyinfo->rolname,
10220                                          "TYPE", SECTION_PRE_DATA,
10221                                          q->data, delq->data, NULL,
10222                                          NULL, 0,
10223                                          NULL, NULL);
10224
10225         /* Dump Type Comments and Security Labels */
10226         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10227                 dumpComment(fout, "TYPE", qtypname,
10228                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10229                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10230
10231         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10232                 dumpSecLabel(fout, "TYPE", qtypname,
10233                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10234                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10235
10236         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10237                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10238                                 qtypname, NULL,
10239                                 tyinfo->dobj.namespace->dobj.name,
10240                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10241                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10242
10243         PQclear(res);
10244         destroyPQExpBuffer(q);
10245         destroyPQExpBuffer(delq);
10246         destroyPQExpBuffer(query);
10247         free(qtypname);
10248         free(qualtypname);
10249 }
10250
10251 /*
10252  * dumpUndefinedType
10253  *        writes out to fout the queries to recreate a !typisdefined type
10254  *
10255  * This is a shell type, but we use different terminology to distinguish
10256  * this case from where we have to emit a shell type definition to break
10257  * circular dependencies.  An undefined type shouldn't ever have anything
10258  * depending on it.
10259  */
10260 static void
10261 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10262 {
10263         DumpOptions *dopt = fout->dopt;
10264         PQExpBuffer q = createPQExpBuffer();
10265         PQExpBuffer delq = createPQExpBuffer();
10266         char       *qtypname;
10267         char       *qualtypname;
10268
10269         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10270         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10271
10272         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10273
10274         if (dopt->binary_upgrade)
10275                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10276                                                                                                  tyinfo->dobj.catId.oid,
10277                                                                                                  false);
10278
10279         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10280                                           qualtypname);
10281
10282         if (dopt->binary_upgrade)
10283                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10284                                                                                 "TYPE", qtypname,
10285                                                                                 tyinfo->dobj.namespace->dobj.name);
10286
10287         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10288                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10289                                          tyinfo->dobj.name,
10290                                          tyinfo->dobj.namespace->dobj.name,
10291                                          NULL,
10292                                          tyinfo->rolname,
10293                                          "TYPE", SECTION_PRE_DATA,
10294                                          q->data, delq->data, NULL,
10295                                          NULL, 0,
10296                                          NULL, NULL);
10297
10298         /* Dump Type Comments and Security Labels */
10299         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10300                 dumpComment(fout, "TYPE", qtypname,
10301                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10302                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10303
10304         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10305                 dumpSecLabel(fout, "TYPE", qtypname,
10306                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10307                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10308
10309         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10310                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10311                                 qtypname, NULL,
10312                                 tyinfo->dobj.namespace->dobj.name,
10313                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10314                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10315
10316         destroyPQExpBuffer(q);
10317         destroyPQExpBuffer(delq);
10318         free(qtypname);
10319         free(qualtypname);
10320 }
10321
10322 /*
10323  * dumpBaseType
10324  *        writes out to fout the queries to recreate a user-defined base type
10325  */
10326 static void
10327 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10328 {
10329         DumpOptions *dopt = fout->dopt;
10330         PQExpBuffer q = createPQExpBuffer();
10331         PQExpBuffer delq = createPQExpBuffer();
10332         PQExpBuffer query = createPQExpBuffer();
10333         PGresult   *res;
10334         char       *qtypname;
10335         char       *qualtypname;
10336         char       *typlen;
10337         char       *typinput;
10338         char       *typoutput;
10339         char       *typreceive;
10340         char       *typsend;
10341         char       *typmodin;
10342         char       *typmodout;
10343         char       *typanalyze;
10344         Oid                     typreceiveoid;
10345         Oid                     typsendoid;
10346         Oid                     typmodinoid;
10347         Oid                     typmodoutoid;
10348         Oid                     typanalyzeoid;
10349         char       *typcategory;
10350         char       *typispreferred;
10351         char       *typdelim;
10352         char       *typbyval;
10353         char       *typalign;
10354         char       *typstorage;
10355         char       *typcollatable;
10356         char       *typdefault;
10357         bool            typdefault_is_literal = false;
10358
10359         /* Fetch type-specific details */
10360         if (fout->remoteVersion >= 90100)
10361         {
10362                 appendPQExpBuffer(query, "SELECT typlen, "
10363                                                   "typinput, typoutput, typreceive, typsend, "
10364                                                   "typmodin, typmodout, typanalyze, "
10365                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10366                                                   "typsend::pg_catalog.oid AS typsendoid, "
10367                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10368                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10369                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10370                                                   "typcategory, typispreferred, "
10371                                                   "typdelim, typbyval, typalign, typstorage, "
10372                                                   "(typcollation <> 0) AS typcollatable, "
10373                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10374                                                   "FROM pg_catalog.pg_type "
10375                                                   "WHERE oid = '%u'::pg_catalog.oid",
10376                                                   tyinfo->dobj.catId.oid);
10377         }
10378         else if (fout->remoteVersion >= 80400)
10379         {
10380                 appendPQExpBuffer(query, "SELECT typlen, "
10381                                                   "typinput, typoutput, typreceive, typsend, "
10382                                                   "typmodin, typmodout, typanalyze, "
10383                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10384                                                   "typsend::pg_catalog.oid AS typsendoid, "
10385                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10386                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10387                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10388                                                   "typcategory, typispreferred, "
10389                                                   "typdelim, typbyval, typalign, typstorage, "
10390                                                   "false AS typcollatable, "
10391                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10392                                                   "FROM pg_catalog.pg_type "
10393                                                   "WHERE oid = '%u'::pg_catalog.oid",
10394                                                   tyinfo->dobj.catId.oid);
10395         }
10396         else if (fout->remoteVersion >= 80300)
10397         {
10398                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10399                 appendPQExpBuffer(query, "SELECT typlen, "
10400                                                   "typinput, typoutput, typreceive, typsend, "
10401                                                   "typmodin, typmodout, typanalyze, "
10402                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10403                                                   "typsend::pg_catalog.oid AS typsendoid, "
10404                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10405                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10406                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10407                                                   "'U' AS typcategory, false AS typispreferred, "
10408                                                   "typdelim, typbyval, typalign, typstorage, "
10409                                                   "false AS typcollatable, "
10410                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10411                                                   "FROM pg_catalog.pg_type "
10412                                                   "WHERE oid = '%u'::pg_catalog.oid",
10413                                                   tyinfo->dobj.catId.oid);
10414         }
10415         else
10416         {
10417                 appendPQExpBuffer(query, "SELECT typlen, "
10418                                                   "typinput, typoutput, typreceive, typsend, "
10419                                                   "'-' AS typmodin, '-' AS typmodout, "
10420                                                   "typanalyze, "
10421                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10422                                                   "typsend::pg_catalog.oid AS typsendoid, "
10423                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10424                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10425                                                   "'U' AS typcategory, false AS typispreferred, "
10426                                                   "typdelim, typbyval, typalign, typstorage, "
10427                                                   "false AS typcollatable, "
10428                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10429                                                   "FROM pg_catalog.pg_type "
10430                                                   "WHERE oid = '%u'::pg_catalog.oid",
10431                                                   tyinfo->dobj.catId.oid);
10432         }
10433
10434         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10435
10436         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10437         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10438         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10439         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10440         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10441         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10442         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10443         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10444         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10445         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10446         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10447         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10448         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10449         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10450         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10451         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10452         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10453         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10454         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10455         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10456         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10457                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10458         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10459         {
10460                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10461                 typdefault_is_literal = true;   /* it needs quotes */
10462         }
10463         else
10464                 typdefault = NULL;
10465
10466         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10467         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10468
10469         /*
10470          * The reason we include CASCADE is that the circular dependency between
10471          * the type and its I/O functions makes it impossible to drop the type any
10472          * other way.
10473          */
10474         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10475
10476         /*
10477          * We might already have a shell type, but setting pg_type_oid is
10478          * harmless, and in any case we'd better set the array type OID.
10479          */
10480         if (dopt->binary_upgrade)
10481                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10482                                                                                                  tyinfo->dobj.catId.oid,
10483                                                                                                  false);
10484
10485         appendPQExpBuffer(q,
10486                                           "CREATE TYPE %s (\n"
10487                                           "    INTERNALLENGTH = %s",
10488                                           qualtypname,
10489                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10490
10491         /* regproc result is sufficiently quoted already */
10492         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10493         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10494         if (OidIsValid(typreceiveoid))
10495                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10496         if (OidIsValid(typsendoid))
10497                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10498         if (OidIsValid(typmodinoid))
10499                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10500         if (OidIsValid(typmodoutoid))
10501                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10502         if (OidIsValid(typanalyzeoid))
10503                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10504
10505         if (strcmp(typcollatable, "t") == 0)
10506                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10507
10508         if (typdefault != NULL)
10509         {
10510                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10511                 if (typdefault_is_literal)
10512                         appendStringLiteralAH(q, typdefault, fout);
10513                 else
10514                         appendPQExpBufferStr(q, typdefault);
10515         }
10516
10517         if (OidIsValid(tyinfo->typelem))
10518         {
10519                 char       *elemType;
10520
10521                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10522                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10523                 free(elemType);
10524         }
10525
10526         if (strcmp(typcategory, "U") != 0)
10527         {
10528                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10529                 appendStringLiteralAH(q, typcategory, fout);
10530         }
10531
10532         if (strcmp(typispreferred, "t") == 0)
10533                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10534
10535         if (typdelim && strcmp(typdelim, ",") != 0)
10536         {
10537                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10538                 appendStringLiteralAH(q, typdelim, fout);
10539         }
10540
10541         if (strcmp(typalign, "c") == 0)
10542                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10543         else if (strcmp(typalign, "s") == 0)
10544                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10545         else if (strcmp(typalign, "i") == 0)
10546                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10547         else if (strcmp(typalign, "d") == 0)
10548                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10549
10550         if (strcmp(typstorage, "p") == 0)
10551                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10552         else if (strcmp(typstorage, "e") == 0)
10553                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10554         else if (strcmp(typstorage, "x") == 0)
10555                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10556         else if (strcmp(typstorage, "m") == 0)
10557                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10558
10559         if (strcmp(typbyval, "t") == 0)
10560                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10561
10562         appendPQExpBufferStr(q, "\n);\n");
10563
10564         if (dopt->binary_upgrade)
10565                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10566                                                                                 "TYPE", qtypname,
10567                                                                                 tyinfo->dobj.namespace->dobj.name);
10568
10569         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10570                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10571                                          tyinfo->dobj.name,
10572                                          tyinfo->dobj.namespace->dobj.name,
10573                                          NULL,
10574                                          tyinfo->rolname,
10575                                          "TYPE", SECTION_PRE_DATA,
10576                                          q->data, delq->data, NULL,
10577                                          NULL, 0,
10578                                          NULL, NULL);
10579
10580         /* Dump Type Comments and Security Labels */
10581         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10582                 dumpComment(fout, "TYPE", qtypname,
10583                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10584                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10585
10586         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10587                 dumpSecLabel(fout, "TYPE", qtypname,
10588                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10589                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10590
10591         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10592                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10593                                 qtypname, NULL,
10594                                 tyinfo->dobj.namespace->dobj.name,
10595                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10596                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10597
10598         PQclear(res);
10599         destroyPQExpBuffer(q);
10600         destroyPQExpBuffer(delq);
10601         destroyPQExpBuffer(query);
10602         free(qtypname);
10603         free(qualtypname);
10604 }
10605
10606 /*
10607  * dumpDomain
10608  *        writes out to fout the queries to recreate a user-defined domain
10609  */
10610 static void
10611 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10612 {
10613         DumpOptions *dopt = fout->dopt;
10614         PQExpBuffer q = createPQExpBuffer();
10615         PQExpBuffer delq = createPQExpBuffer();
10616         PQExpBuffer query = createPQExpBuffer();
10617         PGresult   *res;
10618         int                     i;
10619         char       *qtypname;
10620         char       *qualtypname;
10621         char       *typnotnull;
10622         char       *typdefn;
10623         char       *typdefault;
10624         Oid                     typcollation;
10625         bool            typdefault_is_literal = false;
10626
10627         /* Fetch domain specific details */
10628         if (fout->remoteVersion >= 90100)
10629         {
10630                 /* typcollation is new in 9.1 */
10631                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10632                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10633                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10634                                                   "t.typdefault, "
10635                                                   "CASE WHEN t.typcollation <> u.typcollation "
10636                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10637                                                   "FROM pg_catalog.pg_type t "
10638                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10639                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10640                                                   tyinfo->dobj.catId.oid);
10641         }
10642         else
10643         {
10644                 appendPQExpBuffer(query, "SELECT typnotnull, "
10645                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10646                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10647                                                   "typdefault, 0 AS typcollation "
10648                                                   "FROM pg_catalog.pg_type "
10649                                                   "WHERE oid = '%u'::pg_catalog.oid",
10650                                                   tyinfo->dobj.catId.oid);
10651         }
10652
10653         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10654
10655         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10656         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10657         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10658                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10659         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10660         {
10661                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10662                 typdefault_is_literal = true;   /* it needs quotes */
10663         }
10664         else
10665                 typdefault = NULL;
10666         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10667
10668         if (dopt->binary_upgrade)
10669                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10670                                                                                                  tyinfo->dobj.catId.oid,
10671                                                                                                  true); /* force array type */
10672
10673         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10674         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10675
10676         appendPQExpBuffer(q,
10677                                           "CREATE DOMAIN %s AS %s",
10678                                           qualtypname,
10679                                           typdefn);
10680
10681         /* Print collation only if different from base type's collation */
10682         if (OidIsValid(typcollation))
10683         {
10684                 CollInfo   *coll;
10685
10686                 coll = findCollationByOid(typcollation);
10687                 if (coll)
10688                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10689         }
10690
10691         if (typnotnull[0] == 't')
10692                 appendPQExpBufferStr(q, " NOT NULL");
10693
10694         if (typdefault != NULL)
10695         {
10696                 appendPQExpBufferStr(q, " DEFAULT ");
10697                 if (typdefault_is_literal)
10698                         appendStringLiteralAH(q, typdefault, fout);
10699                 else
10700                         appendPQExpBufferStr(q, typdefault);
10701         }
10702
10703         PQclear(res);
10704
10705         /*
10706          * Add any CHECK constraints for the domain
10707          */
10708         for (i = 0; i < tyinfo->nDomChecks; i++)
10709         {
10710                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10711
10712                 if (!domcheck->separate)
10713                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10714                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10715         }
10716
10717         appendPQExpBufferStr(q, ";\n");
10718
10719         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10720
10721         if (dopt->binary_upgrade)
10722                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10723                                                                                 "DOMAIN", qtypname,
10724                                                                                 tyinfo->dobj.namespace->dobj.name);
10725
10726         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10727                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10728                                          tyinfo->dobj.name,
10729                                          tyinfo->dobj.namespace->dobj.name,
10730                                          NULL,
10731                                          tyinfo->rolname,
10732                                          "DOMAIN", SECTION_PRE_DATA,
10733                                          q->data, delq->data, NULL,
10734                                          NULL, 0,
10735                                          NULL, NULL);
10736
10737         /* Dump Domain Comments and Security Labels */
10738         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10739                 dumpComment(fout, "DOMAIN", qtypname,
10740                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10741                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10742
10743         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10744                 dumpSecLabel(fout, "DOMAIN", qtypname,
10745                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10746                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10747
10748         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10749                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10750                                 qtypname, NULL,
10751                                 tyinfo->dobj.namespace->dobj.name,
10752                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10753                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10754
10755         /* Dump any per-constraint comments */
10756         for (i = 0; i < tyinfo->nDomChecks; i++)
10757         {
10758                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10759                 PQExpBuffer conprefix = createPQExpBuffer();
10760
10761                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10762                                                   fmtId(domcheck->dobj.name));
10763
10764                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10765                         dumpComment(fout, conprefix->data, qtypname,
10766                                                 tyinfo->dobj.namespace->dobj.name,
10767                                                 tyinfo->rolname,
10768                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10769
10770                 destroyPQExpBuffer(conprefix);
10771         }
10772
10773         destroyPQExpBuffer(q);
10774         destroyPQExpBuffer(delq);
10775         destroyPQExpBuffer(query);
10776         free(qtypname);
10777         free(qualtypname);
10778 }
10779
10780 /*
10781  * dumpCompositeType
10782  *        writes out to fout the queries to recreate a user-defined stand-alone
10783  *        composite type
10784  */
10785 static void
10786 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10787 {
10788         DumpOptions *dopt = fout->dopt;
10789         PQExpBuffer q = createPQExpBuffer();
10790         PQExpBuffer dropped = createPQExpBuffer();
10791         PQExpBuffer delq = createPQExpBuffer();
10792         PQExpBuffer query = createPQExpBuffer();
10793         PGresult   *res;
10794         char       *qtypname;
10795         char       *qualtypname;
10796         int                     ntups;
10797         int                     i_attname;
10798         int                     i_atttypdefn;
10799         int                     i_attlen;
10800         int                     i_attalign;
10801         int                     i_attisdropped;
10802         int                     i_attcollation;
10803         int                     i;
10804         int                     actual_atts;
10805
10806         /* Fetch type specific details */
10807         if (fout->remoteVersion >= 90100)
10808         {
10809                 /*
10810                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10811                  * clauses for attributes whose collation is different from their
10812                  * type's default, we use a CASE here to suppress uninteresting
10813                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10814                  * collation does not matter for those.
10815                  */
10816                 appendPQExpBuffer(query, "SELECT a.attname, "
10817                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10818                                                   "a.attlen, a.attalign, a.attisdropped, "
10819                                                   "CASE WHEN a.attcollation <> at.typcollation "
10820                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10821                                                   "FROM pg_catalog.pg_type ct "
10822                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10823                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10824                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10825                                                   "ORDER BY a.attnum ",
10826                                                   tyinfo->dobj.catId.oid);
10827         }
10828         else
10829         {
10830                 /*
10831                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10832                  * should always be false.
10833                  */
10834                 appendPQExpBuffer(query, "SELECT a.attname, "
10835                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10836                                                   "a.attlen, a.attalign, a.attisdropped, "
10837                                                   "0 AS attcollation "
10838                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10839                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10840                                                   "AND a.attrelid = ct.typrelid "
10841                                                   "ORDER BY a.attnum ",
10842                                                   tyinfo->dobj.catId.oid);
10843         }
10844
10845         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10846
10847         ntups = PQntuples(res);
10848
10849         i_attname = PQfnumber(res, "attname");
10850         i_atttypdefn = PQfnumber(res, "atttypdefn");
10851         i_attlen = PQfnumber(res, "attlen");
10852         i_attalign = PQfnumber(res, "attalign");
10853         i_attisdropped = PQfnumber(res, "attisdropped");
10854         i_attcollation = PQfnumber(res, "attcollation");
10855
10856         if (dopt->binary_upgrade)
10857         {
10858                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10859                                                                                                  tyinfo->dobj.catId.oid,
10860                                                                                                  false);
10861                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10862         }
10863
10864         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10865         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10866
10867         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10868                                           qualtypname);
10869
10870         actual_atts = 0;
10871         for (i = 0; i < ntups; i++)
10872         {
10873                 char       *attname;
10874                 char       *atttypdefn;
10875                 char       *attlen;
10876                 char       *attalign;
10877                 bool            attisdropped;
10878                 Oid                     attcollation;
10879
10880                 attname = PQgetvalue(res, i, i_attname);
10881                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10882                 attlen = PQgetvalue(res, i, i_attlen);
10883                 attalign = PQgetvalue(res, i, i_attalign);
10884                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10885                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10886
10887                 if (attisdropped && !dopt->binary_upgrade)
10888                         continue;
10889
10890                 /* Format properly if not first attr */
10891                 if (actual_atts++ > 0)
10892                         appendPQExpBufferChar(q, ',');
10893                 appendPQExpBufferStr(q, "\n\t");
10894
10895                 if (!attisdropped)
10896                 {
10897                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10898
10899                         /* Add collation if not default for the column type */
10900                         if (OidIsValid(attcollation))
10901                         {
10902                                 CollInfo   *coll;
10903
10904                                 coll = findCollationByOid(attcollation);
10905                                 if (coll)
10906                                         appendPQExpBuffer(q, " COLLATE %s",
10907                                                                           fmtQualifiedDumpable(coll));
10908                         }
10909                 }
10910                 else
10911                 {
10912                         /*
10913                          * This is a dropped attribute and we're in binary_upgrade mode.
10914                          * Insert a placeholder for it in the CREATE TYPE command, and set
10915                          * length and alignment with direct UPDATE to the catalogs
10916                          * afterwards. See similar code in dumpTableSchema().
10917                          */
10918                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10919
10920                         /* stash separately for insertion after the CREATE TYPE */
10921                         appendPQExpBufferStr(dropped,
10922                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
10923                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10924                                                           "SET attlen = %s, "
10925                                                           "attalign = '%s', attbyval = false\n"
10926                                                           "WHERE attname = ", attlen, attalign);
10927                         appendStringLiteralAH(dropped, attname, fout);
10928                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
10929                         appendStringLiteralAH(dropped, qualtypname, fout);
10930                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10931
10932                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10933                                                           qualtypname);
10934                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10935                                                           fmtId(attname));
10936                 }
10937         }
10938         appendPQExpBufferStr(q, "\n);\n");
10939         appendPQExpBufferStr(q, dropped->data);
10940
10941         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10942
10943         if (dopt->binary_upgrade)
10944                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10945                                                                                 "TYPE", qtypname,
10946                                                                                 tyinfo->dobj.namespace->dobj.name);
10947
10948         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10949                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10950                                          tyinfo->dobj.name,
10951                                          tyinfo->dobj.namespace->dobj.name,
10952                                          NULL,
10953                                          tyinfo->rolname,
10954                                          "TYPE", SECTION_PRE_DATA,
10955                                          q->data, delq->data, NULL,
10956                                          NULL, 0,
10957                                          NULL, NULL);
10958
10959
10960         /* Dump Type Comments and Security Labels */
10961         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10962                 dumpComment(fout, "TYPE", qtypname,
10963                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10964                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10965
10966         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10967                 dumpSecLabel(fout, "TYPE", qtypname,
10968                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10969                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10970
10971         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10972                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10973                                 qtypname, NULL,
10974                                 tyinfo->dobj.namespace->dobj.name,
10975                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10976                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10977
10978         PQclear(res);
10979         destroyPQExpBuffer(q);
10980         destroyPQExpBuffer(dropped);
10981         destroyPQExpBuffer(delq);
10982         destroyPQExpBuffer(query);
10983         free(qtypname);
10984         free(qualtypname);
10985
10986         /* Dump any per-column comments */
10987         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10988                 dumpCompositeTypeColComments(fout, tyinfo);
10989 }
10990
10991 /*
10992  * dumpCompositeTypeColComments
10993  *        writes out to fout the queries to recreate comments on the columns of
10994  *        a user-defined stand-alone composite type
10995  */
10996 static void
10997 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
10998 {
10999         CommentItem *comments;
11000         int                     ncomments;
11001         PGresult   *res;
11002         PQExpBuffer query;
11003         PQExpBuffer target;
11004         Oid                     pgClassOid;
11005         int                     i;
11006         int                     ntups;
11007         int                     i_attname;
11008         int                     i_attnum;
11009
11010         /* do nothing, if --no-comments is supplied */
11011         if (fout->dopt->no_comments)
11012                 return;
11013
11014         query = createPQExpBuffer();
11015
11016         appendPQExpBuffer(query,
11017                                           "SELECT c.tableoid, a.attname, a.attnum "
11018                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11019                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11020                                           "  AND NOT a.attisdropped "
11021                                           "ORDER BY a.attnum ",
11022                                           tyinfo->typrelid);
11023
11024         /* Fetch column attnames */
11025         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11026
11027         ntups = PQntuples(res);
11028         if (ntups < 1)
11029         {
11030                 PQclear(res);
11031                 destroyPQExpBuffer(query);
11032                 return;
11033         }
11034
11035         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11036
11037         /* Search for comments associated with type's pg_class OID */
11038         ncomments = findComments(fout,
11039                                                          pgClassOid,
11040                                                          tyinfo->typrelid,
11041                                                          &comments);
11042
11043         /* If no comments exist, we're done */
11044         if (ncomments <= 0)
11045         {
11046                 PQclear(res);
11047                 destroyPQExpBuffer(query);
11048                 return;
11049         }
11050
11051         /* Build COMMENT ON statements */
11052         target = createPQExpBuffer();
11053
11054         i_attnum = PQfnumber(res, "attnum");
11055         i_attname = PQfnumber(res, "attname");
11056         while (ncomments > 0)
11057         {
11058                 const char *attname;
11059
11060                 attname = NULL;
11061                 for (i = 0; i < ntups; i++)
11062                 {
11063                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11064                         {
11065                                 attname = PQgetvalue(res, i, i_attname);
11066                                 break;
11067                         }
11068                 }
11069                 if (attname)                    /* just in case we don't find it */
11070                 {
11071                         const char *descr = comments->descr;
11072
11073                         resetPQExpBuffer(target);
11074                         appendPQExpBuffer(target, "COLUMN %s.",
11075                                                           fmtId(tyinfo->dobj.name));
11076                         appendPQExpBufferStr(target, fmtId(attname));
11077
11078                         resetPQExpBuffer(query);
11079                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11080                                                           fmtQualifiedDumpable(tyinfo));
11081                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11082                         appendStringLiteralAH(query, descr, fout);
11083                         appendPQExpBufferStr(query, ";\n");
11084
11085                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11086                                                  target->data,
11087                                                  tyinfo->dobj.namespace->dobj.name,
11088                                                  NULL, tyinfo->rolname,
11089                                                  "COMMENT", SECTION_NONE,
11090                                                  query->data, "", NULL,
11091                                                  &(tyinfo->dobj.dumpId), 1,
11092                                                  NULL, NULL);
11093                 }
11094
11095                 comments++;
11096                 ncomments--;
11097         }
11098
11099         PQclear(res);
11100         destroyPQExpBuffer(query);
11101         destroyPQExpBuffer(target);
11102 }
11103
11104 /*
11105  * dumpShellType
11106  *        writes out to fout the queries to create a shell type
11107  *
11108  * We dump a shell definition in advance of the I/O functions for the type.
11109  */
11110 static void
11111 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11112 {
11113         DumpOptions *dopt = fout->dopt;
11114         PQExpBuffer q;
11115
11116         /* Skip if not to be dumped */
11117         if (!stinfo->dobj.dump || dopt->dataOnly)
11118                 return;
11119
11120         q = createPQExpBuffer();
11121
11122         /*
11123          * Note the lack of a DROP command for the shell type; any required DROP
11124          * is driven off the base type entry, instead.  This interacts with
11125          * _printTocEntry()'s use of the presence of a DROP command to decide
11126          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11127          * the shell type's owner immediately on creation; that should happen only
11128          * after it's filled in, otherwise the backend complains.
11129          */
11130
11131         if (dopt->binary_upgrade)
11132                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11133                                                                                                  stinfo->baseType->dobj.catId.oid,
11134                                                                                                  false);
11135
11136         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11137                                           fmtQualifiedDumpable(stinfo));
11138
11139         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11140                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11141                                          stinfo->dobj.name,
11142                                          stinfo->dobj.namespace->dobj.name,
11143                                          NULL,
11144                                          stinfo->baseType->rolname,
11145                                          "SHELL TYPE", SECTION_PRE_DATA,
11146                                          q->data, "", NULL,
11147                                          NULL, 0,
11148                                          NULL, NULL);
11149
11150         destroyPQExpBuffer(q);
11151 }
11152
11153 /*
11154  * dumpProcLang
11155  *                writes out to fout the queries to recreate a user-defined
11156  *                procedural language
11157  */
11158 static void
11159 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11160 {
11161         DumpOptions *dopt = fout->dopt;
11162         PQExpBuffer defqry;
11163         PQExpBuffer delqry;
11164         bool            useParams;
11165         char       *qlanname;
11166         FuncInfo   *funcInfo;
11167         FuncInfo   *inlineInfo = NULL;
11168         FuncInfo   *validatorInfo = NULL;
11169
11170         /* Skip if not to be dumped */
11171         if (!plang->dobj.dump || dopt->dataOnly)
11172                 return;
11173
11174         /*
11175          * Try to find the support function(s).  It is not an error if we don't
11176          * find them --- if the functions are in the pg_catalog schema, as is
11177          * standard in 8.1 and up, then we won't have loaded them. (In this case
11178          * we will emit a parameterless CREATE LANGUAGE command, which will
11179          * require PL template knowledge in the backend to reload.)
11180          */
11181
11182         funcInfo = findFuncByOid(plang->lanplcallfoid);
11183         if (funcInfo != NULL && !funcInfo->dobj.dump)
11184                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11185
11186         if (OidIsValid(plang->laninline))
11187         {
11188                 inlineInfo = findFuncByOid(plang->laninline);
11189                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11190                         inlineInfo = NULL;
11191         }
11192
11193         if (OidIsValid(plang->lanvalidator))
11194         {
11195                 validatorInfo = findFuncByOid(plang->lanvalidator);
11196                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11197                         validatorInfo = NULL;
11198         }
11199
11200         /*
11201          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11202          * with parameters.  Otherwise, we'll write a parameterless command, which
11203          * will rely on data from pg_pltemplate.
11204          */
11205         useParams = (funcInfo != NULL &&
11206                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11207                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11208
11209         defqry = createPQExpBuffer();
11210         delqry = createPQExpBuffer();
11211
11212         qlanname = pg_strdup(fmtId(plang->dobj.name));
11213
11214         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11215                                           qlanname);
11216
11217         if (useParams)
11218         {
11219                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11220                                                   plang->lanpltrusted ? "TRUSTED " : "",
11221                                                   qlanname);
11222                 appendPQExpBuffer(defqry, " HANDLER %s",
11223                                                   fmtQualifiedDumpable(funcInfo));
11224                 if (OidIsValid(plang->laninline))
11225                         appendPQExpBuffer(defqry, " INLINE %s",
11226                                                           fmtQualifiedDumpable(inlineInfo));
11227                 if (OidIsValid(plang->lanvalidator))
11228                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11229                                                           fmtQualifiedDumpable(validatorInfo));
11230         }
11231         else
11232         {
11233                 /*
11234                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11235                  * command will not fail if the language is preinstalled in the target
11236                  * database.  We restrict the use of REPLACE to this case so as to
11237                  * eliminate the risk of replacing a language with incompatible
11238                  * parameter settings: this command will only succeed at all if there
11239                  * is a pg_pltemplate entry, and if there is one, the existing entry
11240                  * must match it too.
11241                  */
11242                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11243                                                   qlanname);
11244         }
11245         appendPQExpBufferStr(defqry, ";\n");
11246
11247         if (dopt->binary_upgrade)
11248                 binary_upgrade_extension_member(defqry, &plang->dobj,
11249                                                                                 "LANGUAGE", qlanname, NULL);
11250
11251         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11252                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11253                                          plang->dobj.name,
11254                                          NULL, NULL, plang->lanowner,
11255                                          "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11256                                          defqry->data, delqry->data, NULL,
11257                                          NULL, 0,
11258                                          NULL, NULL);
11259
11260         /* Dump Proc Lang Comments and Security Labels */
11261         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11262                 dumpComment(fout, "LANGUAGE", qlanname,
11263                                         NULL, plang->lanowner,
11264                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11265
11266         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11267                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11268                                          NULL, plang->lanowner,
11269                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11270
11271         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11272                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11273                                 qlanname, NULL, NULL,
11274                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11275                                 plang->initlanacl, plang->initrlanacl);
11276
11277         free(qlanname);
11278
11279         destroyPQExpBuffer(defqry);
11280         destroyPQExpBuffer(delqry);
11281 }
11282
11283 /*
11284  * format_function_arguments: generate function name and argument list
11285  *
11286  * This is used when we can rely on pg_get_function_arguments to format
11287  * the argument list.  Note, however, that pg_get_function_arguments
11288  * does not special-case zero-argument aggregates.
11289  */
11290 static char *
11291 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11292 {
11293         PQExpBufferData fn;
11294
11295         initPQExpBuffer(&fn);
11296         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11297         if (is_agg && finfo->nargs == 0)
11298                 appendPQExpBufferStr(&fn, "(*)");
11299         else
11300                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11301         return fn.data;
11302 }
11303
11304 /*
11305  * format_function_arguments_old: generate function name and argument list
11306  *
11307  * The argument type names are qualified if needed.  The function name
11308  * is never qualified.
11309  *
11310  * This is used only with pre-8.4 servers, so we aren't expecting to see
11311  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11312  *
11313  * Any or all of allargtypes, argmodes, argnames may be NULL.
11314  */
11315 static char *
11316 format_function_arguments_old(Archive *fout,
11317                                                           FuncInfo *finfo, int nallargs,
11318                                                           char **allargtypes,
11319                                                           char **argmodes,
11320                                                           char **argnames)
11321 {
11322         PQExpBufferData fn;
11323         int                     j;
11324
11325         initPQExpBuffer(&fn);
11326         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11327         for (j = 0; j < nallargs; j++)
11328         {
11329                 Oid                     typid;
11330                 char       *typname;
11331                 const char *argmode;
11332                 const char *argname;
11333
11334                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11335                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11336
11337                 if (argmodes)
11338                 {
11339                         switch (argmodes[j][0])
11340                         {
11341                                 case PROARGMODE_IN:
11342                                         argmode = "";
11343                                         break;
11344                                 case PROARGMODE_OUT:
11345                                         argmode = "OUT ";
11346                                         break;
11347                                 case PROARGMODE_INOUT:
11348                                         argmode = "INOUT ";
11349                                         break;
11350                                 default:
11351                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11352                                         argmode = "";
11353                                         break;
11354                         }
11355                 }
11356                 else
11357                         argmode = "";
11358
11359                 argname = argnames ? argnames[j] : (char *) NULL;
11360                 if (argname && argname[0] == '\0')
11361                         argname = NULL;
11362
11363                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11364                                                   (j > 0) ? ", " : "",
11365                                                   argmode,
11366                                                   argname ? fmtId(argname) : "",
11367                                                   argname ? " " : "",
11368                                                   typname);
11369                 free(typname);
11370         }
11371         appendPQExpBufferChar(&fn, ')');
11372         return fn.data;
11373 }
11374
11375 /*
11376  * format_function_signature: generate function name and argument list
11377  *
11378  * This is like format_function_arguments_old except that only a minimal
11379  * list of input argument types is generated; this is sufficient to
11380  * reference the function, but not to define it.
11381  *
11382  * If honor_quotes is false then the function name is never quoted.
11383  * This is appropriate for use in TOC tags, but not in SQL commands.
11384  */
11385 static char *
11386 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11387 {
11388         PQExpBufferData fn;
11389         int                     j;
11390
11391         initPQExpBuffer(&fn);
11392         if (honor_quotes)
11393                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11394         else
11395                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11396         for (j = 0; j < finfo->nargs; j++)
11397         {
11398                 char       *typname;
11399
11400                 if (j > 0)
11401                         appendPQExpBufferStr(&fn, ", ");
11402
11403                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11404                                                                            zeroAsOpaque);
11405                 appendPQExpBufferStr(&fn, typname);
11406                 free(typname);
11407         }
11408         appendPQExpBufferChar(&fn, ')');
11409         return fn.data;
11410 }
11411
11412
11413 /*
11414  * dumpFunc:
11415  *        dump out one function
11416  */
11417 static void
11418 dumpFunc(Archive *fout, FuncInfo *finfo)
11419 {
11420         DumpOptions *dopt = fout->dopt;
11421         PQExpBuffer query;
11422         PQExpBuffer q;
11423         PQExpBuffer delqry;
11424         PQExpBuffer asPart;
11425         PGresult   *res;
11426         char       *funcsig;            /* identity signature */
11427         char       *funcfullsig = NULL; /* full signature */
11428         char       *funcsig_tag;
11429         char       *proretset;
11430         char       *prosrc;
11431         char       *probin;
11432         char       *funcargs;
11433         char       *funciargs;
11434         char       *funcresult;
11435         char       *proallargtypes;
11436         char       *proargmodes;
11437         char       *proargnames;
11438         char       *protrftypes;
11439         char       *prokind;
11440         char       *provolatile;
11441         char       *proisstrict;
11442         char       *prosecdef;
11443         char       *proleakproof;
11444         char       *proconfig;
11445         char       *procost;
11446         char       *prorows;
11447         char       *proparallel;
11448         char       *lanname;
11449         char       *rettypename;
11450         int                     nallargs;
11451         char      **allargtypes = NULL;
11452         char      **argmodes = NULL;
11453         char      **argnames = NULL;
11454         char      **configitems = NULL;
11455         int                     nconfigitems = 0;
11456         const char *keyword;
11457         int                     i;
11458
11459         /* Skip if not to be dumped */
11460         if (!finfo->dobj.dump || dopt->dataOnly)
11461                 return;
11462
11463         query = createPQExpBuffer();
11464         q = createPQExpBuffer();
11465         delqry = createPQExpBuffer();
11466         asPart = createPQExpBuffer();
11467
11468         /* Fetch function-specific details */
11469         if (fout->remoteVersion >= 110000)
11470         {
11471                 /*
11472                  * prokind was added in 11
11473                  */
11474                 appendPQExpBuffer(query,
11475                                                   "SELECT proretset, prosrc, probin, "
11476                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11477                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11478                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11479                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11480                                                   "prokind, provolatile, proisstrict, prosecdef, "
11481                                                   "proleakproof, proconfig, procost, prorows, "
11482                                                   "proparallel, "
11483                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11484                                                   "FROM pg_catalog.pg_proc "
11485                                                   "WHERE oid = '%u'::pg_catalog.oid",
11486                                                   finfo->dobj.catId.oid);
11487         }
11488         else if (fout->remoteVersion >= 90600)
11489         {
11490                 /*
11491                  * proparallel was added in 9.6
11492                  */
11493                 appendPQExpBuffer(query,
11494                                                   "SELECT proretset, prosrc, probin, "
11495                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11496                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11497                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11498                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11499                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11500                                                   "provolatile, proisstrict, prosecdef, "
11501                                                   "proleakproof, proconfig, procost, prorows, "
11502                                                   "proparallel, "
11503                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11504                                                   "FROM pg_catalog.pg_proc "
11505                                                   "WHERE oid = '%u'::pg_catalog.oid",
11506                                                   finfo->dobj.catId.oid);
11507         }
11508         else if (fout->remoteVersion >= 90500)
11509         {
11510                 /*
11511                  * protrftypes was added in 9.5
11512                  */
11513                 appendPQExpBuffer(query,
11514                                                   "SELECT proretset, prosrc, probin, "
11515                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11516                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11517                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11518                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11519                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11520                                                   "provolatile, proisstrict, prosecdef, "
11521                                                   "proleakproof, proconfig, procost, prorows, "
11522                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11523                                                   "FROM pg_catalog.pg_proc "
11524                                                   "WHERE oid = '%u'::pg_catalog.oid",
11525                                                   finfo->dobj.catId.oid);
11526         }
11527         else if (fout->remoteVersion >= 90200)
11528         {
11529                 /*
11530                  * proleakproof was added in 9.2
11531                  */
11532                 appendPQExpBuffer(query,
11533                                                   "SELECT proretset, prosrc, probin, "
11534                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11535                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11536                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11537                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11538                                                   "provolatile, proisstrict, prosecdef, "
11539                                                   "proleakproof, proconfig, procost, prorows, "
11540                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11541                                                   "FROM pg_catalog.pg_proc "
11542                                                   "WHERE oid = '%u'::pg_catalog.oid",
11543                                                   finfo->dobj.catId.oid);
11544         }
11545         else if (fout->remoteVersion >= 80400)
11546         {
11547                 /*
11548                  * In 8.4 and up we rely on pg_get_function_arguments and
11549                  * pg_get_function_result instead of examining proallargtypes etc.
11550                  */
11551                 appendPQExpBuffer(query,
11552                                                   "SELECT proretset, prosrc, probin, "
11553                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11554                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11555                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11556                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11557                                                   "provolatile, proisstrict, prosecdef, "
11558                                                   "false AS proleakproof, "
11559                                                   " proconfig, procost, prorows, "
11560                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11561                                                   "FROM pg_catalog.pg_proc "
11562                                                   "WHERE oid = '%u'::pg_catalog.oid",
11563                                                   finfo->dobj.catId.oid);
11564         }
11565         else if (fout->remoteVersion >= 80300)
11566         {
11567                 appendPQExpBuffer(query,
11568                                                   "SELECT proretset, prosrc, probin, "
11569                                                   "proallargtypes, proargmodes, proargnames, "
11570                                                   "'f' AS prokind, "
11571                                                   "provolatile, proisstrict, prosecdef, "
11572                                                   "false AS proleakproof, "
11573                                                   "proconfig, procost, prorows, "
11574                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11575                                                   "FROM pg_catalog.pg_proc "
11576                                                   "WHERE oid = '%u'::pg_catalog.oid",
11577                                                   finfo->dobj.catId.oid);
11578         }
11579         else if (fout->remoteVersion >= 80100)
11580         {
11581                 appendPQExpBuffer(query,
11582                                                   "SELECT proretset, prosrc, probin, "
11583                                                   "proallargtypes, proargmodes, proargnames, "
11584                                                   "'f' AS prokind, "
11585                                                   "provolatile, proisstrict, prosecdef, "
11586                                                   "false AS proleakproof, "
11587                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11588                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11589                                                   "FROM pg_catalog.pg_proc "
11590                                                   "WHERE oid = '%u'::pg_catalog.oid",
11591                                                   finfo->dobj.catId.oid);
11592         }
11593         else
11594         {
11595                 appendPQExpBuffer(query,
11596                                                   "SELECT proretset, prosrc, probin, "
11597                                                   "null AS proallargtypes, "
11598                                                   "null AS proargmodes, "
11599                                                   "proargnames, "
11600                                                   "'f' AS prokind, "
11601                                                   "provolatile, proisstrict, prosecdef, "
11602                                                   "false AS proleakproof, "
11603                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11604                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11605                                                   "FROM pg_catalog.pg_proc "
11606                                                   "WHERE oid = '%u'::pg_catalog.oid",
11607                                                   finfo->dobj.catId.oid);
11608         }
11609
11610         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11611
11612         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11613         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11614         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11615         if (fout->remoteVersion >= 80400)
11616         {
11617                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11618                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11619                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11620                 proallargtypes = proargmodes = proargnames = NULL;
11621         }
11622         else
11623         {
11624                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11625                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11626                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11627                 funcargs = funciargs = funcresult = NULL;
11628         }
11629         if (PQfnumber(res, "protrftypes") != -1)
11630                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11631         else
11632                 protrftypes = NULL;
11633         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11634         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11635         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11636         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11637         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11638         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11639         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11640         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11641
11642         if (PQfnumber(res, "proparallel") != -1)
11643                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11644         else
11645                 proparallel = NULL;
11646
11647         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11648
11649         /*
11650          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11651          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11652          * versions would set it to "-".  There are no known cases in which prosrc
11653          * is unused, so the tests below for "-" are probably useless.
11654          */
11655         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11656         {
11657                 appendPQExpBufferStr(asPart, "AS ");
11658                 appendStringLiteralAH(asPart, probin, fout);
11659                 if (strcmp(prosrc, "-") != 0)
11660                 {
11661                         appendPQExpBufferStr(asPart, ", ");
11662
11663                         /*
11664                          * where we have bin, use dollar quoting if allowed and src
11665                          * contains quote or backslash; else use regular quoting.
11666                          */
11667                         if (dopt->disable_dollar_quoting ||
11668                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11669                                 appendStringLiteralAH(asPart, prosrc, fout);
11670                         else
11671                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11672                 }
11673         }
11674         else
11675         {
11676                 if (strcmp(prosrc, "-") != 0)
11677                 {
11678                         appendPQExpBufferStr(asPart, "AS ");
11679                         /* with no bin, dollar quote src unconditionally if allowed */
11680                         if (dopt->disable_dollar_quoting)
11681                                 appendStringLiteralAH(asPart, prosrc, fout);
11682                         else
11683                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11684                 }
11685         }
11686
11687         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11688
11689         if (proallargtypes && *proallargtypes)
11690         {
11691                 int                     nitems = 0;
11692
11693                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11694                         nitems < finfo->nargs)
11695                 {
11696                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11697                         if (allargtypes)
11698                                 free(allargtypes);
11699                         allargtypes = NULL;
11700                 }
11701                 else
11702                         nallargs = nitems;
11703         }
11704
11705         if (proargmodes && *proargmodes)
11706         {
11707                 int                     nitems = 0;
11708
11709                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11710                         nitems != nallargs)
11711                 {
11712                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11713                         if (argmodes)
11714                                 free(argmodes);
11715                         argmodes = NULL;
11716                 }
11717         }
11718
11719         if (proargnames && *proargnames)
11720         {
11721                 int                     nitems = 0;
11722
11723                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11724                         nitems != nallargs)
11725                 {
11726                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11727                         if (argnames)
11728                                 free(argnames);
11729                         argnames = NULL;
11730                 }
11731         }
11732
11733         if (proconfig && *proconfig)
11734         {
11735                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11736                 {
11737                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11738                         if (configitems)
11739                                 free(configitems);
11740                         configitems = NULL;
11741                         nconfigitems = 0;
11742                 }
11743         }
11744
11745         if (funcargs)
11746         {
11747                 /* 8.4 or later; we rely on server-side code for most of the work */
11748                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11749                 funcsig = format_function_arguments(finfo, funciargs, false);
11750         }
11751         else
11752                 /* pre-8.4, do it ourselves */
11753                 funcsig = format_function_arguments_old(fout,
11754                                                                                                 finfo, nallargs, allargtypes,
11755                                                                                                 argmodes, argnames);
11756
11757         funcsig_tag = format_function_signature(fout, finfo, false);
11758
11759         if (prokind[0] == PROKIND_PROCEDURE)
11760                 keyword = "PROCEDURE";
11761         else
11762                 keyword = "FUNCTION";   /* works for window functions too */
11763
11764         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11765                                           keyword,
11766                                           fmtId(finfo->dobj.namespace->dobj.name),
11767                                           funcsig);
11768
11769         appendPQExpBuffer(q, "CREATE %s %s.%s",
11770                                           keyword,
11771                                           fmtId(finfo->dobj.namespace->dobj.name),
11772                                           funcfullsig ? funcfullsig :
11773                                           funcsig);
11774
11775         if (prokind[0] == PROKIND_PROCEDURE)
11776                  /* no result type to output */ ;
11777         else if (funcresult)
11778                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11779         else
11780         {
11781                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11782                                                                                    zeroAsOpaque);
11783                 appendPQExpBuffer(q, " RETURNS %s%s",
11784                                                   (proretset[0] == 't') ? "SETOF " : "",
11785                                                   rettypename);
11786                 free(rettypename);
11787         }
11788
11789         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11790
11791         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11792         {
11793                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11794                 int                     i;
11795
11796                 appendPQExpBufferStr(q, " TRANSFORM ");
11797                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11798                 for (i = 0; typeids[i]; i++)
11799                 {
11800                         if (i != 0)
11801                                 appendPQExpBufferStr(q, ", ");
11802                         appendPQExpBuffer(q, "FOR TYPE %s",
11803                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11804                 }
11805         }
11806
11807         if (prokind[0] == PROKIND_WINDOW)
11808                 appendPQExpBufferStr(q, " WINDOW");
11809
11810         if (provolatile[0] != PROVOLATILE_VOLATILE)
11811         {
11812                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11813                         appendPQExpBufferStr(q, " IMMUTABLE");
11814                 else if (provolatile[0] == PROVOLATILE_STABLE)
11815                         appendPQExpBufferStr(q, " STABLE");
11816                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11817                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11818                                                   finfo->dobj.name);
11819         }
11820
11821         if (proisstrict[0] == 't')
11822                 appendPQExpBufferStr(q, " STRICT");
11823
11824         if (prosecdef[0] == 't')
11825                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11826
11827         if (proleakproof[0] == 't')
11828                 appendPQExpBufferStr(q, " LEAKPROOF");
11829
11830         /*
11831          * COST and ROWS are emitted only if present and not default, so as not to
11832          * break backwards-compatibility of the dump without need.  Keep this code
11833          * in sync with the defaults in functioncmds.c.
11834          */
11835         if (strcmp(procost, "0") != 0)
11836         {
11837                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11838                 {
11839                         /* default cost is 1 */
11840                         if (strcmp(procost, "1") != 0)
11841                                 appendPQExpBuffer(q, " COST %s", procost);
11842                 }
11843                 else
11844                 {
11845                         /* default cost is 100 */
11846                         if (strcmp(procost, "100") != 0)
11847                                 appendPQExpBuffer(q, " COST %s", procost);
11848                 }
11849         }
11850         if (proretset[0] == 't' &&
11851                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11852                 appendPQExpBuffer(q, " ROWS %s", prorows);
11853
11854         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11855         {
11856                 if (proparallel[0] == PROPARALLEL_SAFE)
11857                         appendPQExpBufferStr(q, " PARALLEL SAFE");
11858                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11859                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11860                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
11861                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11862                                                   finfo->dobj.name);
11863         }
11864
11865         for (i = 0; i < nconfigitems; i++)
11866         {
11867                 /* we feel free to scribble on configitems[] here */
11868                 char       *configitem = configitems[i];
11869                 char       *pos;
11870
11871                 pos = strchr(configitem, '=');
11872                 if (pos == NULL)
11873                         continue;
11874                 *pos++ = '\0';
11875                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
11876
11877                 /*
11878                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
11879                  * by flatten_set_variable_args() before they were put into the
11880                  * proconfig array.  However, because the quoting rules used there
11881                  * aren't exactly like SQL's, we have to break the list value apart
11882                  * and then quote the elements as string literals.  (The elements may
11883                  * be double-quoted as-is, but we can't just feed them to the SQL
11884                  * parser; it would do the wrong thing with elements that are
11885                  * zero-length or longer than NAMEDATALEN.)
11886                  *
11887                  * Variables that are not so marked should just be emitted as simple
11888                  * string literals.  If the variable is not known to
11889                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
11890                  * to use GUC_LIST_QUOTE for extension variables.
11891                  */
11892                 if (variable_is_guc_list_quote(configitem))
11893                 {
11894                         char      **namelist;
11895                         char      **nameptr;
11896
11897                         /* Parse string into list of identifiers */
11898                         /* this shouldn't fail really */
11899                         if (SplitGUCList(pos, ',', &namelist))
11900                         {
11901                                 for (nameptr = namelist; *nameptr; nameptr++)
11902                                 {
11903                                         if (nameptr != namelist)
11904                                                 appendPQExpBufferStr(q, ", ");
11905                                         appendStringLiteralAH(q, *nameptr, fout);
11906                                 }
11907                         }
11908                         pg_free(namelist);
11909                 }
11910                 else
11911                         appendStringLiteralAH(q, pos, fout);
11912         }
11913
11914         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
11915
11916         if (dopt->binary_upgrade)
11917                 binary_upgrade_extension_member(q, &finfo->dobj,
11918                                                                                 keyword, funcsig,
11919                                                                                 finfo->dobj.namespace->dobj.name);
11920
11921         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11922                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11923                                          funcsig_tag,
11924                                          finfo->dobj.namespace->dobj.name,
11925                                          NULL,
11926                                          finfo->rolname,
11927                                          keyword, SECTION_PRE_DATA,
11928                                          q->data, delqry->data, NULL,
11929                                          NULL, 0,
11930                                          NULL, NULL);
11931
11932         /* Dump Function Comments and Security Labels */
11933         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11934                 dumpComment(fout, keyword, funcsig,
11935                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
11936                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
11937
11938         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11939                 dumpSecLabel(fout, keyword, funcsig,
11940                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
11941                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
11942
11943         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
11944                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
11945                                 funcsig, NULL,
11946                                 finfo->dobj.namespace->dobj.name,
11947                                 finfo->rolname, finfo->proacl, finfo->rproacl,
11948                                 finfo->initproacl, finfo->initrproacl);
11949
11950         PQclear(res);
11951
11952         destroyPQExpBuffer(query);
11953         destroyPQExpBuffer(q);
11954         destroyPQExpBuffer(delqry);
11955         destroyPQExpBuffer(asPart);
11956         free(funcsig);
11957         if (funcfullsig)
11958                 free(funcfullsig);
11959         free(funcsig_tag);
11960         if (allargtypes)
11961                 free(allargtypes);
11962         if (argmodes)
11963                 free(argmodes);
11964         if (argnames)
11965                 free(argnames);
11966         if (configitems)
11967                 free(configitems);
11968 }
11969
11970
11971 /*
11972  * Dump a user-defined cast
11973  */
11974 static void
11975 dumpCast(Archive *fout, CastInfo *cast)
11976 {
11977         DumpOptions *dopt = fout->dopt;
11978         PQExpBuffer defqry;
11979         PQExpBuffer delqry;
11980         PQExpBuffer labelq;
11981         PQExpBuffer castargs;
11982         FuncInfo   *funcInfo = NULL;
11983         char       *sourceType;
11984         char       *targetType;
11985
11986         /* Skip if not to be dumped */
11987         if (!cast->dobj.dump || dopt->dataOnly)
11988                 return;
11989
11990         /* Cannot dump if we don't have the cast function's info */
11991         if (OidIsValid(cast->castfunc))
11992         {
11993                 funcInfo = findFuncByOid(cast->castfunc);
11994                 if (funcInfo == NULL)
11995                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
11996                                                   cast->castfunc);
11997         }
11998
11999         defqry = createPQExpBuffer();
12000         delqry = createPQExpBuffer();
12001         labelq = createPQExpBuffer();
12002         castargs = createPQExpBuffer();
12003
12004         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12005         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12006         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12007                                           sourceType, targetType);
12008
12009         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12010                                           sourceType, targetType);
12011
12012         switch (cast->castmethod)
12013         {
12014                 case COERCION_METHOD_BINARY:
12015                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12016                         break;
12017                 case COERCION_METHOD_INOUT:
12018                         appendPQExpBufferStr(defqry, "WITH INOUT");
12019                         break;
12020                 case COERCION_METHOD_FUNCTION:
12021                         if (funcInfo)
12022                         {
12023                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12024
12025                                 /*
12026                                  * Always qualify the function name (format_function_signature
12027                                  * won't qualify it).
12028                                  */
12029                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12030                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12031                                 free(fsig);
12032                         }
12033                         else
12034                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12035                         break;
12036                 default:
12037                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12038         }
12039
12040         if (cast->castcontext == 'a')
12041                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12042         else if (cast->castcontext == 'i')
12043                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12044         appendPQExpBufferStr(defqry, ";\n");
12045
12046         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12047                                           sourceType, targetType);
12048
12049         appendPQExpBuffer(castargs, "(%s AS %s)",
12050                                           sourceType, targetType);
12051
12052         if (dopt->binary_upgrade)
12053                 binary_upgrade_extension_member(defqry, &cast->dobj,
12054                                                                                 "CAST", castargs->data, NULL);
12055
12056         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12057                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12058                                          labelq->data,
12059                                          NULL, NULL, "",
12060                                          "CAST", SECTION_PRE_DATA,
12061                                          defqry->data, delqry->data, NULL,
12062                                          NULL, 0,
12063                                          NULL, NULL);
12064
12065         /* Dump Cast Comments */
12066         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12067                 dumpComment(fout, "CAST", castargs->data,
12068                                         NULL, "",
12069                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12070
12071         free(sourceType);
12072         free(targetType);
12073
12074         destroyPQExpBuffer(defqry);
12075         destroyPQExpBuffer(delqry);
12076         destroyPQExpBuffer(labelq);
12077         destroyPQExpBuffer(castargs);
12078 }
12079
12080 /*
12081  * Dump a transform
12082  */
12083 static void
12084 dumpTransform(Archive *fout, TransformInfo *transform)
12085 {
12086         DumpOptions *dopt = fout->dopt;
12087         PQExpBuffer defqry;
12088         PQExpBuffer delqry;
12089         PQExpBuffer labelq;
12090         PQExpBuffer transformargs;
12091         FuncInfo   *fromsqlFuncInfo = NULL;
12092         FuncInfo   *tosqlFuncInfo = NULL;
12093         char       *lanname;
12094         char       *transformType;
12095
12096         /* Skip if not to be dumped */
12097         if (!transform->dobj.dump || dopt->dataOnly)
12098                 return;
12099
12100         /* Cannot dump if we don't have the transform functions' info */
12101         if (OidIsValid(transform->trffromsql))
12102         {
12103                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12104                 if (fromsqlFuncInfo == NULL)
12105                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12106                                                   transform->trffromsql);
12107         }
12108         if (OidIsValid(transform->trftosql))
12109         {
12110                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12111                 if (tosqlFuncInfo == NULL)
12112                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12113                                                   transform->trftosql);
12114         }
12115
12116         defqry = createPQExpBuffer();
12117         delqry = createPQExpBuffer();
12118         labelq = createPQExpBuffer();
12119         transformargs = createPQExpBuffer();
12120
12121         lanname = get_language_name(fout, transform->trflang);
12122         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12123
12124         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12125                                           transformType, lanname);
12126
12127         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12128                                           transformType, lanname);
12129
12130         if (!transform->trffromsql && !transform->trftosql)
12131                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12132
12133         if (transform->trffromsql)
12134         {
12135                 if (fromsqlFuncInfo)
12136                 {
12137                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12138
12139                         /*
12140                          * Always qualify the function name (format_function_signature
12141                          * won't qualify it).
12142                          */
12143                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12144                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12145                         free(fsig);
12146                 }
12147                 else
12148                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12149         }
12150
12151         if (transform->trftosql)
12152         {
12153                 if (transform->trffromsql)
12154                         appendPQExpBuffer(defqry, ", ");
12155
12156                 if (tosqlFuncInfo)
12157                 {
12158                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12159
12160                         /*
12161                          * Always qualify the function name (format_function_signature
12162                          * won't qualify it).
12163                          */
12164                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12165                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12166                         free(fsig);
12167                 }
12168                 else
12169                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12170         }
12171
12172         appendPQExpBuffer(defqry, ");\n");
12173
12174         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12175                                           transformType, lanname);
12176
12177         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12178                                           transformType, lanname);
12179
12180         if (dopt->binary_upgrade)
12181                 binary_upgrade_extension_member(defqry, &transform->dobj,
12182                                                                                 "TRANSFORM", transformargs->data, NULL);
12183
12184         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12185                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12186                                          labelq->data,
12187                                          NULL, NULL, "",
12188                                          "TRANSFORM", SECTION_PRE_DATA,
12189                                          defqry->data, delqry->data, NULL,
12190                                          transform->dobj.dependencies, transform->dobj.nDeps,
12191                                          NULL, NULL);
12192
12193         /* Dump Transform Comments */
12194         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12195                 dumpComment(fout, "TRANSFORM", transformargs->data,
12196                                         NULL, "",
12197                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12198
12199         free(lanname);
12200         free(transformType);
12201         destroyPQExpBuffer(defqry);
12202         destroyPQExpBuffer(delqry);
12203         destroyPQExpBuffer(labelq);
12204         destroyPQExpBuffer(transformargs);
12205 }
12206
12207
12208 /*
12209  * dumpOpr
12210  *        write out a single operator definition
12211  */
12212 static void
12213 dumpOpr(Archive *fout, OprInfo *oprinfo)
12214 {
12215         DumpOptions *dopt = fout->dopt;
12216         PQExpBuffer query;
12217         PQExpBuffer q;
12218         PQExpBuffer delq;
12219         PQExpBuffer oprid;
12220         PQExpBuffer details;
12221         PGresult   *res;
12222         int                     i_oprkind;
12223         int                     i_oprcode;
12224         int                     i_oprleft;
12225         int                     i_oprright;
12226         int                     i_oprcom;
12227         int                     i_oprnegate;
12228         int                     i_oprrest;
12229         int                     i_oprjoin;
12230         int                     i_oprcanmerge;
12231         int                     i_oprcanhash;
12232         char       *oprkind;
12233         char       *oprcode;
12234         char       *oprleft;
12235         char       *oprright;
12236         char       *oprcom;
12237         char       *oprnegate;
12238         char       *oprrest;
12239         char       *oprjoin;
12240         char       *oprcanmerge;
12241         char       *oprcanhash;
12242         char       *oprregproc;
12243         char       *oprref;
12244
12245         /* Skip if not to be dumped */
12246         if (!oprinfo->dobj.dump || dopt->dataOnly)
12247                 return;
12248
12249         /*
12250          * some operators are invalid because they were the result of user
12251          * defining operators before commutators exist
12252          */
12253         if (!OidIsValid(oprinfo->oprcode))
12254                 return;
12255
12256         query = createPQExpBuffer();
12257         q = createPQExpBuffer();
12258         delq = createPQExpBuffer();
12259         oprid = createPQExpBuffer();
12260         details = createPQExpBuffer();
12261
12262         if (fout->remoteVersion >= 80300)
12263         {
12264                 appendPQExpBuffer(query, "SELECT oprkind, "
12265                                                   "oprcode::pg_catalog.regprocedure, "
12266                                                   "oprleft::pg_catalog.regtype, "
12267                                                   "oprright::pg_catalog.regtype, "
12268                                                   "oprcom, "
12269                                                   "oprnegate, "
12270                                                   "oprrest::pg_catalog.regprocedure, "
12271                                                   "oprjoin::pg_catalog.regprocedure, "
12272                                                   "oprcanmerge, oprcanhash "
12273                                                   "FROM pg_catalog.pg_operator "
12274                                                   "WHERE oid = '%u'::pg_catalog.oid",
12275                                                   oprinfo->dobj.catId.oid);
12276         }
12277         else
12278         {
12279                 appendPQExpBuffer(query, "SELECT oprkind, "
12280                                                   "oprcode::pg_catalog.regprocedure, "
12281                                                   "oprleft::pg_catalog.regtype, "
12282                                                   "oprright::pg_catalog.regtype, "
12283                                                   "oprcom, "
12284                                                   "oprnegate, "
12285                                                   "oprrest::pg_catalog.regprocedure, "
12286                                                   "oprjoin::pg_catalog.regprocedure, "
12287                                                   "(oprlsortop != 0) AS oprcanmerge, "
12288                                                   "oprcanhash "
12289                                                   "FROM pg_catalog.pg_operator "
12290                                                   "WHERE oid = '%u'::pg_catalog.oid",
12291                                                   oprinfo->dobj.catId.oid);
12292         }
12293
12294         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12295
12296         i_oprkind = PQfnumber(res, "oprkind");
12297         i_oprcode = PQfnumber(res, "oprcode");
12298         i_oprleft = PQfnumber(res, "oprleft");
12299         i_oprright = PQfnumber(res, "oprright");
12300         i_oprcom = PQfnumber(res, "oprcom");
12301         i_oprnegate = PQfnumber(res, "oprnegate");
12302         i_oprrest = PQfnumber(res, "oprrest");
12303         i_oprjoin = PQfnumber(res, "oprjoin");
12304         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12305         i_oprcanhash = PQfnumber(res, "oprcanhash");
12306
12307         oprkind = PQgetvalue(res, 0, i_oprkind);
12308         oprcode = PQgetvalue(res, 0, i_oprcode);
12309         oprleft = PQgetvalue(res, 0, i_oprleft);
12310         oprright = PQgetvalue(res, 0, i_oprright);
12311         oprcom = PQgetvalue(res, 0, i_oprcom);
12312         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12313         oprrest = PQgetvalue(res, 0, i_oprrest);
12314         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12315         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12316         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12317
12318         oprregproc = convertRegProcReference(fout, oprcode);
12319         if (oprregproc)
12320         {
12321                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12322                 free(oprregproc);
12323         }
12324
12325         appendPQExpBuffer(oprid, "%s (",
12326                                           oprinfo->dobj.name);
12327
12328         /*
12329          * right unary means there's a left arg and left unary means there's a
12330          * right arg
12331          */
12332         if (strcmp(oprkind, "r") == 0 ||
12333                 strcmp(oprkind, "b") == 0)
12334         {
12335                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12336                 appendPQExpBufferStr(oprid, oprleft);
12337         }
12338         else
12339                 appendPQExpBufferStr(oprid, "NONE");
12340
12341         if (strcmp(oprkind, "l") == 0 ||
12342                 strcmp(oprkind, "b") == 0)
12343         {
12344                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12345                 appendPQExpBuffer(oprid, ", %s)", oprright);
12346         }
12347         else
12348                 appendPQExpBufferStr(oprid, ", NONE)");
12349
12350         oprref = getFormattedOperatorName(fout, oprcom);
12351         if (oprref)
12352         {
12353                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12354                 free(oprref);
12355         }
12356
12357         oprref = getFormattedOperatorName(fout, oprnegate);
12358         if (oprref)
12359         {
12360                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12361                 free(oprref);
12362         }
12363
12364         if (strcmp(oprcanmerge, "t") == 0)
12365                 appendPQExpBufferStr(details, ",\n    MERGES");
12366
12367         if (strcmp(oprcanhash, "t") == 0)
12368                 appendPQExpBufferStr(details, ",\n    HASHES");
12369
12370         oprregproc = convertRegProcReference(fout, oprrest);
12371         if (oprregproc)
12372         {
12373                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12374                 free(oprregproc);
12375         }
12376
12377         oprregproc = convertRegProcReference(fout, oprjoin);
12378         if (oprregproc)
12379         {
12380                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12381                 free(oprregproc);
12382         }
12383
12384         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12385                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12386                                           oprid->data);
12387
12388         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12389                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12390                                           oprinfo->dobj.name, details->data);
12391
12392         if (dopt->binary_upgrade)
12393                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12394                                                                                 "OPERATOR", oprid->data,
12395                                                                                 oprinfo->dobj.namespace->dobj.name);
12396
12397         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12398                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12399                                          oprinfo->dobj.name,
12400                                          oprinfo->dobj.namespace->dobj.name,
12401                                          NULL,
12402                                          oprinfo->rolname,
12403                                          "OPERATOR", SECTION_PRE_DATA,
12404                                          q->data, delq->data, NULL,
12405                                          NULL, 0,
12406                                          NULL, NULL);
12407
12408         /* Dump Operator Comments */
12409         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12410                 dumpComment(fout, "OPERATOR", oprid->data,
12411                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12412                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12413
12414         PQclear(res);
12415
12416         destroyPQExpBuffer(query);
12417         destroyPQExpBuffer(q);
12418         destroyPQExpBuffer(delq);
12419         destroyPQExpBuffer(oprid);
12420         destroyPQExpBuffer(details);
12421 }
12422
12423 /*
12424  * Convert a function reference obtained from pg_operator
12425  *
12426  * Returns allocated string of what to print, or NULL if function references
12427  * is InvalidOid. Returned string is expected to be free'd by the caller.
12428  *
12429  * The input is a REGPROCEDURE display; we have to strip the argument-types
12430  * part.
12431  */
12432 static char *
12433 convertRegProcReference(Archive *fout, const char *proc)
12434 {
12435         char       *name;
12436         char       *paren;
12437         bool            inquote;
12438
12439         /* In all cases "-" means a null reference */
12440         if (strcmp(proc, "-") == 0)
12441                 return NULL;
12442
12443         name = pg_strdup(proc);
12444         /* find non-double-quoted left paren */
12445         inquote = false;
12446         for (paren = name; *paren; paren++)
12447         {
12448                 if (*paren == '(' && !inquote)
12449                 {
12450                         *paren = '\0';
12451                         break;
12452                 }
12453                 if (*paren == '"')
12454                         inquote = !inquote;
12455         }
12456         return name;
12457 }
12458
12459 /*
12460  * getFormattedOperatorName - retrieve the operator name for the
12461  * given operator OID (presented in string form).
12462  *
12463  * Returns an allocated string, or NULL if the given OID is invalid.
12464  * Caller is responsible for free'ing result string.
12465  *
12466  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12467  * useful in commands where the operator's argument types can be inferred from
12468  * context.  We always schema-qualify the name, though.  The predecessor to
12469  * this code tried to skip the schema qualification if possible, but that led
12470  * to wrong results in corner cases, such as if an operator and its negator
12471  * are in different schemas.
12472  */
12473 static char *
12474 getFormattedOperatorName(Archive *fout, const char *oproid)
12475 {
12476         OprInfo    *oprInfo;
12477
12478         /* In all cases "0" means a null reference */
12479         if (strcmp(oproid, "0") == 0)
12480                 return NULL;
12481
12482         oprInfo = findOprByOid(atooid(oproid));
12483         if (oprInfo == NULL)
12484         {
12485                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12486                                   oproid);
12487                 return NULL;
12488         }
12489
12490         return psprintf("OPERATOR(%s.%s)",
12491                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12492                                         oprInfo->dobj.name);
12493 }
12494
12495 /*
12496  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12497  *
12498  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12499  * argument lists of these functions are predetermined.  Note that the
12500  * caller should ensure we are in the proper schema, because the results
12501  * are search path dependent!
12502  */
12503 static char *
12504 convertTSFunction(Archive *fout, Oid funcOid)
12505 {
12506         char       *result;
12507         char            query[128];
12508         PGresult   *res;
12509
12510         snprintf(query, sizeof(query),
12511                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12512         res = ExecuteSqlQueryForSingleRow(fout, query);
12513
12514         result = pg_strdup(PQgetvalue(res, 0, 0));
12515
12516         PQclear(res);
12517
12518         return result;
12519 }
12520
12521 /*
12522  * dumpAccessMethod
12523  *        write out a single access method definition
12524  */
12525 static void
12526 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12527 {
12528         DumpOptions *dopt = fout->dopt;
12529         PQExpBuffer q;
12530         PQExpBuffer delq;
12531         char       *qamname;
12532
12533         /* Skip if not to be dumped */
12534         if (!aminfo->dobj.dump || dopt->dataOnly)
12535                 return;
12536
12537         q = createPQExpBuffer();
12538         delq = createPQExpBuffer();
12539
12540         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12541
12542         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12543
12544         switch (aminfo->amtype)
12545         {
12546                 case AMTYPE_INDEX:
12547                         appendPQExpBuffer(q, "TYPE INDEX ");
12548                         break;
12549                 default:
12550                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12551                                           aminfo->amtype, qamname);
12552                         destroyPQExpBuffer(q);
12553                         destroyPQExpBuffer(delq);
12554                         free(qamname);
12555                         return;
12556         }
12557
12558         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12559
12560         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12561                                           qamname);
12562
12563         if (dopt->binary_upgrade)
12564                 binary_upgrade_extension_member(q, &aminfo->dobj,
12565                                                                                 "ACCESS METHOD", qamname, NULL);
12566
12567         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12568                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12569                                          aminfo->dobj.name,
12570                                          NULL,
12571                                          NULL,
12572                                          "",
12573                                          "ACCESS METHOD", SECTION_PRE_DATA,
12574                                          q->data, delq->data, NULL,
12575                                          NULL, 0,
12576                                          NULL, NULL);
12577
12578         /* Dump Access Method Comments */
12579         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12580                 dumpComment(fout, "ACCESS METHOD", qamname,
12581                                         NULL, "",
12582                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12583
12584         destroyPQExpBuffer(q);
12585         destroyPQExpBuffer(delq);
12586         free(qamname);
12587 }
12588
12589 /*
12590  * dumpOpclass
12591  *        write out a single operator class definition
12592  */
12593 static void
12594 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12595 {
12596         DumpOptions *dopt = fout->dopt;
12597         PQExpBuffer query;
12598         PQExpBuffer q;
12599         PQExpBuffer delq;
12600         PQExpBuffer nameusing;
12601         PGresult   *res;
12602         int                     ntups;
12603         int                     i_opcintype;
12604         int                     i_opckeytype;
12605         int                     i_opcdefault;
12606         int                     i_opcfamily;
12607         int                     i_opcfamilyname;
12608         int                     i_opcfamilynsp;
12609         int                     i_amname;
12610         int                     i_amopstrategy;
12611         int                     i_amopreqcheck;
12612         int                     i_amopopr;
12613         int                     i_sortfamily;
12614         int                     i_sortfamilynsp;
12615         int                     i_amprocnum;
12616         int                     i_amproc;
12617         int                     i_amproclefttype;
12618         int                     i_amprocrighttype;
12619         char       *opcintype;
12620         char       *opckeytype;
12621         char       *opcdefault;
12622         char       *opcfamily;
12623         char       *opcfamilyname;
12624         char       *opcfamilynsp;
12625         char       *amname;
12626         char       *amopstrategy;
12627         char       *amopreqcheck;
12628         char       *amopopr;
12629         char       *sortfamily;
12630         char       *sortfamilynsp;
12631         char       *amprocnum;
12632         char       *amproc;
12633         char       *amproclefttype;
12634         char       *amprocrighttype;
12635         bool            needComma;
12636         int                     i;
12637
12638         /* Skip if not to be dumped */
12639         if (!opcinfo->dobj.dump || dopt->dataOnly)
12640                 return;
12641
12642         query = createPQExpBuffer();
12643         q = createPQExpBuffer();
12644         delq = createPQExpBuffer();
12645         nameusing = createPQExpBuffer();
12646
12647         /* Get additional fields from the pg_opclass row */
12648         if (fout->remoteVersion >= 80300)
12649         {
12650                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12651                                                   "opckeytype::pg_catalog.regtype, "
12652                                                   "opcdefault, opcfamily, "
12653                                                   "opfname AS opcfamilyname, "
12654                                                   "nspname AS opcfamilynsp, "
12655                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12656                                                   "FROM pg_catalog.pg_opclass c "
12657                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12658                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12659                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12660                                                   opcinfo->dobj.catId.oid);
12661         }
12662         else
12663         {
12664                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12665                                                   "opckeytype::pg_catalog.regtype, "
12666                                                   "opcdefault, NULL AS opcfamily, "
12667                                                   "NULL AS opcfamilyname, "
12668                                                   "NULL AS opcfamilynsp, "
12669                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12670                                                   "FROM pg_catalog.pg_opclass "
12671                                                   "WHERE oid = '%u'::pg_catalog.oid",
12672                                                   opcinfo->dobj.catId.oid);
12673         }
12674
12675         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12676
12677         i_opcintype = PQfnumber(res, "opcintype");
12678         i_opckeytype = PQfnumber(res, "opckeytype");
12679         i_opcdefault = PQfnumber(res, "opcdefault");
12680         i_opcfamily = PQfnumber(res, "opcfamily");
12681         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12682         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12683         i_amname = PQfnumber(res, "amname");
12684
12685         /* opcintype may still be needed after we PQclear res */
12686         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12687         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12688         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12689         /* opcfamily will still be needed after we PQclear res */
12690         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12691         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12692         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12693         /* amname will still be needed after we PQclear res */
12694         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12695
12696         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12697                                           fmtQualifiedDumpable(opcinfo));
12698         appendPQExpBuffer(delq, " USING %s;\n",
12699                                           fmtId(amname));
12700
12701         /* Build the fixed portion of the CREATE command */
12702         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12703                                           fmtQualifiedDumpable(opcinfo));
12704         if (strcmp(opcdefault, "t") == 0)
12705                 appendPQExpBufferStr(q, "DEFAULT ");
12706         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12707                                           opcintype,
12708                                           fmtId(amname));
12709         if (strlen(opcfamilyname) > 0)
12710         {
12711                 appendPQExpBufferStr(q, " FAMILY ");
12712                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12713                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12714         }
12715         appendPQExpBufferStr(q, " AS\n    ");
12716
12717         needComma = false;
12718
12719         if (strcmp(opckeytype, "-") != 0)
12720         {
12721                 appendPQExpBuffer(q, "STORAGE %s",
12722                                                   opckeytype);
12723                 needComma = true;
12724         }
12725
12726         PQclear(res);
12727
12728         /*
12729          * Now fetch and print the OPERATOR entries (pg_amop rows).
12730          *
12731          * Print only those opfamily members that are tied to the opclass by
12732          * pg_depend entries.
12733          *
12734          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12735          * older server's opclass in which it is used.  This is to avoid
12736          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12737          * older server and then reload into that old version.  This can go away
12738          * once 8.3 is so old as to not be of interest to anyone.
12739          */
12740         resetPQExpBuffer(query);
12741
12742         if (fout->remoteVersion >= 90100)
12743         {
12744                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12745                                                   "amopopr::pg_catalog.regoperator, "
12746                                                   "opfname AS sortfamily, "
12747                                                   "nspname AS sortfamilynsp "
12748                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12749                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12750                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12751                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12752                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12753                                                   "AND refobjid = '%u'::pg_catalog.oid "
12754                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12755                                                   "ORDER BY amopstrategy",
12756                                                   opcinfo->dobj.catId.oid,
12757                                                   opcfamily);
12758         }
12759         else if (fout->remoteVersion >= 80400)
12760         {
12761                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12762                                                   "amopopr::pg_catalog.regoperator, "
12763                                                   "NULL AS sortfamily, "
12764                                                   "NULL AS sortfamilynsp "
12765                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12766                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12767                                                   "AND refobjid = '%u'::pg_catalog.oid "
12768                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12769                                                   "AND objid = ao.oid "
12770                                                   "ORDER BY amopstrategy",
12771                                                   opcinfo->dobj.catId.oid);
12772         }
12773         else if (fout->remoteVersion >= 80300)
12774         {
12775                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12776                                                   "amopopr::pg_catalog.regoperator, "
12777                                                   "NULL AS sortfamily, "
12778                                                   "NULL AS sortfamilynsp "
12779                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12780                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12781                                                   "AND refobjid = '%u'::pg_catalog.oid "
12782                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12783                                                   "AND objid = ao.oid "
12784                                                   "ORDER BY amopstrategy",
12785                                                   opcinfo->dobj.catId.oid);
12786         }
12787         else
12788         {
12789                 /*
12790                  * Here, we print all entries since there are no opfamilies and hence
12791                  * no loose operators to worry about.
12792                  */
12793                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12794                                                   "amopopr::pg_catalog.regoperator, "
12795                                                   "NULL AS sortfamily, "
12796                                                   "NULL AS sortfamilynsp "
12797                                                   "FROM pg_catalog.pg_amop "
12798                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12799                                                   "ORDER BY amopstrategy",
12800                                                   opcinfo->dobj.catId.oid);
12801         }
12802
12803         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12804
12805         ntups = PQntuples(res);
12806
12807         i_amopstrategy = PQfnumber(res, "amopstrategy");
12808         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12809         i_amopopr = PQfnumber(res, "amopopr");
12810         i_sortfamily = PQfnumber(res, "sortfamily");
12811         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12812
12813         for (i = 0; i < ntups; i++)
12814         {
12815                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12816                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12817                 amopopr = PQgetvalue(res, i, i_amopopr);
12818                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12819                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12820
12821                 if (needComma)
12822                         appendPQExpBufferStr(q, " ,\n    ");
12823
12824                 appendPQExpBuffer(q, "OPERATOR %s %s",
12825                                                   amopstrategy, amopopr);
12826
12827                 if (strlen(sortfamily) > 0)
12828                 {
12829                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12830                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12831                         appendPQExpBufferStr(q, fmtId(sortfamily));
12832                 }
12833
12834                 if (strcmp(amopreqcheck, "t") == 0)
12835                         appendPQExpBufferStr(q, " RECHECK");
12836
12837                 needComma = true;
12838         }
12839
12840         PQclear(res);
12841
12842         /*
12843          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12844          *
12845          * Print only those opfamily members that are tied to the opclass by
12846          * pg_depend entries.
12847          *
12848          * We print the amproclefttype/amprocrighttype even though in most cases
12849          * the backend could deduce the right values, because of the corner case
12850          * of a btree sort support function for a cross-type comparison.  That's
12851          * only allowed in 9.2 and later, but for simplicity print them in all
12852          * versions that have the columns.
12853          */
12854         resetPQExpBuffer(query);
12855
12856         if (fout->remoteVersion >= 80300)
12857         {
12858                 appendPQExpBuffer(query, "SELECT amprocnum, "
12859                                                   "amproc::pg_catalog.regprocedure, "
12860                                                   "amproclefttype::pg_catalog.regtype, "
12861                                                   "amprocrighttype::pg_catalog.regtype "
12862                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12863                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12864                                                   "AND refobjid = '%u'::pg_catalog.oid "
12865                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12866                                                   "AND objid = ap.oid "
12867                                                   "ORDER BY amprocnum",
12868                                                   opcinfo->dobj.catId.oid);
12869         }
12870         else
12871         {
12872                 appendPQExpBuffer(query, "SELECT amprocnum, "
12873                                                   "amproc::pg_catalog.regprocedure, "
12874                                                   "'' AS amproclefttype, "
12875                                                   "'' AS amprocrighttype "
12876                                                   "FROM pg_catalog.pg_amproc "
12877                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12878                                                   "ORDER BY amprocnum",
12879                                                   opcinfo->dobj.catId.oid);
12880         }
12881
12882         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12883
12884         ntups = PQntuples(res);
12885
12886         i_amprocnum = PQfnumber(res, "amprocnum");
12887         i_amproc = PQfnumber(res, "amproc");
12888         i_amproclefttype = PQfnumber(res, "amproclefttype");
12889         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12890
12891         for (i = 0; i < ntups; i++)
12892         {
12893                 amprocnum = PQgetvalue(res, i, i_amprocnum);
12894                 amproc = PQgetvalue(res, i, i_amproc);
12895                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12896                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12897
12898                 if (needComma)
12899                         appendPQExpBufferStr(q, " ,\n    ");
12900
12901                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12902
12903                 if (*amproclefttype && *amprocrighttype)
12904                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12905
12906                 appendPQExpBuffer(q, " %s", amproc);
12907
12908                 needComma = true;
12909         }
12910
12911         PQclear(res);
12912
12913         /*
12914          * If needComma is still false it means we haven't added anything after
12915          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
12916          * clause with the same datatype.  This isn't sanctioned by the
12917          * documentation, but actually DefineOpClass will treat it as a no-op.
12918          */
12919         if (!needComma)
12920                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
12921
12922         appendPQExpBufferStr(q, ";\n");
12923
12924         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
12925         appendPQExpBuffer(nameusing, " USING %s",
12926                                           fmtId(amname));
12927
12928         if (dopt->binary_upgrade)
12929                 binary_upgrade_extension_member(q, &opcinfo->dobj,
12930                                                                                 "OPERATOR CLASS", nameusing->data,
12931                                                                                 opcinfo->dobj.namespace->dobj.name);
12932
12933         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12934                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12935                                          opcinfo->dobj.name,
12936                                          opcinfo->dobj.namespace->dobj.name,
12937                                          NULL,
12938                                          opcinfo->rolname,
12939                                          "OPERATOR CLASS", SECTION_PRE_DATA,
12940                                          q->data, delq->data, NULL,
12941                                          NULL, 0,
12942                                          NULL, NULL);
12943
12944         /* Dump Operator Class Comments */
12945         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12946                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
12947                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
12948                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
12949
12950         free(opcintype);
12951         free(opcfamily);
12952         free(amname);
12953         destroyPQExpBuffer(query);
12954         destroyPQExpBuffer(q);
12955         destroyPQExpBuffer(delq);
12956         destroyPQExpBuffer(nameusing);
12957 }
12958
12959 /*
12960  * dumpOpfamily
12961  *        write out a single operator family definition
12962  *
12963  * Note: this also dumps any "loose" operator members that aren't bound to a
12964  * specific opclass within the opfamily.
12965  */
12966 static void
12967 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
12968 {
12969         DumpOptions *dopt = fout->dopt;
12970         PQExpBuffer query;
12971         PQExpBuffer q;
12972         PQExpBuffer delq;
12973         PQExpBuffer nameusing;
12974         PGresult   *res;
12975         PGresult   *res_ops;
12976         PGresult   *res_procs;
12977         int                     ntups;
12978         int                     i_amname;
12979         int                     i_amopstrategy;
12980         int                     i_amopreqcheck;
12981         int                     i_amopopr;
12982         int                     i_sortfamily;
12983         int                     i_sortfamilynsp;
12984         int                     i_amprocnum;
12985         int                     i_amproc;
12986         int                     i_amproclefttype;
12987         int                     i_amprocrighttype;
12988         char       *amname;
12989         char       *amopstrategy;
12990         char       *amopreqcheck;
12991         char       *amopopr;
12992         char       *sortfamily;
12993         char       *sortfamilynsp;
12994         char       *amprocnum;
12995         char       *amproc;
12996         char       *amproclefttype;
12997         char       *amprocrighttype;
12998         bool            needComma;
12999         int                     i;
13000
13001         /* Skip if not to be dumped */
13002         if (!opfinfo->dobj.dump || dopt->dataOnly)
13003                 return;
13004
13005         query = createPQExpBuffer();
13006         q = createPQExpBuffer();
13007         delq = createPQExpBuffer();
13008         nameusing = createPQExpBuffer();
13009
13010         /*
13011          * Fetch only those opfamily members that are tied directly to the
13012          * opfamily by pg_depend entries.
13013          *
13014          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13015          * older server's opclass in which it is used.  This is to avoid
13016          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13017          * older server and then reload into that old version.  This can go away
13018          * once 8.3 is so old as to not be of interest to anyone.
13019          */
13020         if (fout->remoteVersion >= 90100)
13021         {
13022                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13023                                                   "amopopr::pg_catalog.regoperator, "
13024                                                   "opfname AS sortfamily, "
13025                                                   "nspname AS sortfamilynsp "
13026                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13027                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13028                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13029                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13030                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13031                                                   "AND refobjid = '%u'::pg_catalog.oid "
13032                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13033                                                   "ORDER BY amopstrategy",
13034                                                   opfinfo->dobj.catId.oid,
13035                                                   opfinfo->dobj.catId.oid);
13036         }
13037         else if (fout->remoteVersion >= 80400)
13038         {
13039                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13040                                                   "amopopr::pg_catalog.regoperator, "
13041                                                   "NULL AS sortfamily, "
13042                                                   "NULL AS sortfamilynsp "
13043                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13044                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13045                                                   "AND refobjid = '%u'::pg_catalog.oid "
13046                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13047                                                   "AND objid = ao.oid "
13048                                                   "ORDER BY amopstrategy",
13049                                                   opfinfo->dobj.catId.oid);
13050         }
13051         else
13052         {
13053                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13054                                                   "amopopr::pg_catalog.regoperator, "
13055                                                   "NULL AS sortfamily, "
13056                                                   "NULL AS sortfamilynsp "
13057                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13058                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13059                                                   "AND refobjid = '%u'::pg_catalog.oid "
13060                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13061                                                   "AND objid = ao.oid "
13062                                                   "ORDER BY amopstrategy",
13063                                                   opfinfo->dobj.catId.oid);
13064         }
13065
13066         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13067
13068         resetPQExpBuffer(query);
13069
13070         appendPQExpBuffer(query, "SELECT amprocnum, "
13071                                           "amproc::pg_catalog.regprocedure, "
13072                                           "amproclefttype::pg_catalog.regtype, "
13073                                           "amprocrighttype::pg_catalog.regtype "
13074                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13075                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13076                                           "AND refobjid = '%u'::pg_catalog.oid "
13077                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13078                                           "AND objid = ap.oid "
13079                                           "ORDER BY amprocnum",
13080                                           opfinfo->dobj.catId.oid);
13081
13082         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13083
13084         /* Get additional fields from the pg_opfamily row */
13085         resetPQExpBuffer(query);
13086
13087         appendPQExpBuffer(query, "SELECT "
13088                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13089                                           "FROM pg_catalog.pg_opfamily "
13090                                           "WHERE oid = '%u'::pg_catalog.oid",
13091                                           opfinfo->dobj.catId.oid);
13092
13093         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13094
13095         i_amname = PQfnumber(res, "amname");
13096
13097         /* amname will still be needed after we PQclear res */
13098         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13099
13100         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13101                                           fmtQualifiedDumpable(opfinfo));
13102         appendPQExpBuffer(delq, " USING %s;\n",
13103                                           fmtId(amname));
13104
13105         /* Build the fixed portion of the CREATE command */
13106         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13107                                           fmtQualifiedDumpable(opfinfo));
13108         appendPQExpBuffer(q, " USING %s;\n",
13109                                           fmtId(amname));
13110
13111         PQclear(res);
13112
13113         /* Do we need an ALTER to add loose members? */
13114         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13115         {
13116                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13117                                                   fmtQualifiedDumpable(opfinfo));
13118                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13119                                                   fmtId(amname));
13120
13121                 needComma = false;
13122
13123                 /*
13124                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13125                  */
13126                 ntups = PQntuples(res_ops);
13127
13128                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13129                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13130                 i_amopopr = PQfnumber(res_ops, "amopopr");
13131                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13132                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13133
13134                 for (i = 0; i < ntups; i++)
13135                 {
13136                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13137                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13138                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13139                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13140                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13141
13142                         if (needComma)
13143                                 appendPQExpBufferStr(q, " ,\n    ");
13144
13145                         appendPQExpBuffer(q, "OPERATOR %s %s",
13146                                                           amopstrategy, amopopr);
13147
13148                         if (strlen(sortfamily) > 0)
13149                         {
13150                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13151                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13152                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13153                         }
13154
13155                         if (strcmp(amopreqcheck, "t") == 0)
13156                                 appendPQExpBufferStr(q, " RECHECK");
13157
13158                         needComma = true;
13159                 }
13160
13161                 /*
13162                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13163                  */
13164                 ntups = PQntuples(res_procs);
13165
13166                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13167                 i_amproc = PQfnumber(res_procs, "amproc");
13168                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13169                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13170
13171                 for (i = 0; i < ntups; i++)
13172                 {
13173                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13174                         amproc = PQgetvalue(res_procs, i, i_amproc);
13175                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13176                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13177
13178                         if (needComma)
13179                                 appendPQExpBufferStr(q, " ,\n    ");
13180
13181                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13182                                                           amprocnum, amproclefttype, amprocrighttype,
13183                                                           amproc);
13184
13185                         needComma = true;
13186                 }
13187
13188                 appendPQExpBufferStr(q, ";\n");
13189         }
13190
13191         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13192         appendPQExpBuffer(nameusing, " USING %s",
13193                                           fmtId(amname));
13194
13195         if (dopt->binary_upgrade)
13196                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13197                                                                                 "OPERATOR FAMILY", nameusing->data,
13198                                                                                 opfinfo->dobj.namespace->dobj.name);
13199
13200         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13201                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13202                                          opfinfo->dobj.name,
13203                                          opfinfo->dobj.namespace->dobj.name,
13204                                          NULL,
13205                                          opfinfo->rolname,
13206                                          "OPERATOR FAMILY", SECTION_PRE_DATA,
13207                                          q->data, delq->data, NULL,
13208                                          NULL, 0,
13209                                          NULL, NULL);
13210
13211         /* Dump Operator Family Comments */
13212         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13213                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13214                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13215                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13216
13217         free(amname);
13218         PQclear(res_ops);
13219         PQclear(res_procs);
13220         destroyPQExpBuffer(query);
13221         destroyPQExpBuffer(q);
13222         destroyPQExpBuffer(delq);
13223         destroyPQExpBuffer(nameusing);
13224 }
13225
13226 /*
13227  * dumpCollation
13228  *        write out a single collation definition
13229  */
13230 static void
13231 dumpCollation(Archive *fout, CollInfo *collinfo)
13232 {
13233         DumpOptions *dopt = fout->dopt;
13234         PQExpBuffer query;
13235         PQExpBuffer q;
13236         PQExpBuffer delq;
13237         char       *qcollname;
13238         PGresult   *res;
13239         int                     i_collprovider;
13240         int                     i_collcollate;
13241         int                     i_collctype;
13242         const char *collprovider;
13243         const char *collcollate;
13244         const char *collctype;
13245
13246         /* Skip if not to be dumped */
13247         if (!collinfo->dobj.dump || dopt->dataOnly)
13248                 return;
13249
13250         query = createPQExpBuffer();
13251         q = createPQExpBuffer();
13252         delq = createPQExpBuffer();
13253
13254         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13255
13256         /* Get collation-specific details */
13257         if (fout->remoteVersion >= 100000)
13258                 appendPQExpBuffer(query, "SELECT "
13259                                                   "collprovider, "
13260                                                   "collcollate, "
13261                                                   "collctype, "
13262                                                   "collversion "
13263                                                   "FROM pg_catalog.pg_collation c "
13264                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13265                                                   collinfo->dobj.catId.oid);
13266         else
13267                 appendPQExpBuffer(query, "SELECT "
13268                                                   "'c' AS collprovider, "
13269                                                   "collcollate, "
13270                                                   "collctype, "
13271                                                   "NULL AS collversion "
13272                                                   "FROM pg_catalog.pg_collation c "
13273                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13274                                                   collinfo->dobj.catId.oid);
13275
13276         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13277
13278         i_collprovider = PQfnumber(res, "collprovider");
13279         i_collcollate = PQfnumber(res, "collcollate");
13280         i_collctype = PQfnumber(res, "collctype");
13281
13282         collprovider = PQgetvalue(res, 0, i_collprovider);
13283         collcollate = PQgetvalue(res, 0, i_collcollate);
13284         collctype = PQgetvalue(res, 0, i_collctype);
13285
13286         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13287                                           fmtQualifiedDumpable(collinfo));
13288
13289         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13290                                           fmtQualifiedDumpable(collinfo));
13291
13292         appendPQExpBufferStr(q, "provider = ");
13293         if (collprovider[0] == 'c')
13294                 appendPQExpBufferStr(q, "libc");
13295         else if (collprovider[0] == 'i')
13296                 appendPQExpBufferStr(q, "icu");
13297         else if (collprovider[0] == 'd')
13298                 /* to allow dumping pg_catalog; not accepted on input */
13299                 appendPQExpBufferStr(q, "default");
13300         else
13301                 exit_horribly(NULL,
13302                                           "unrecognized collation provider: %s\n",
13303                                           collprovider);
13304
13305         if (strcmp(collcollate, collctype) == 0)
13306         {
13307                 appendPQExpBufferStr(q, ", locale = ");
13308                 appendStringLiteralAH(q, collcollate, fout);
13309         }
13310         else
13311         {
13312                 appendPQExpBufferStr(q, ", lc_collate = ");
13313                 appendStringLiteralAH(q, collcollate, fout);
13314                 appendPQExpBufferStr(q, ", lc_ctype = ");
13315                 appendStringLiteralAH(q, collctype, fout);
13316         }
13317
13318         /*
13319          * For binary upgrade, carry over the collation version.  For normal
13320          * dump/restore, omit the version, so that it is computed upon restore.
13321          */
13322         if (dopt->binary_upgrade)
13323         {
13324                 int                     i_collversion;
13325
13326                 i_collversion = PQfnumber(res, "collversion");
13327                 if (!PQgetisnull(res, 0, i_collversion))
13328                 {
13329                         appendPQExpBufferStr(q, ", version = ");
13330                         appendStringLiteralAH(q,
13331                                                                   PQgetvalue(res, 0, i_collversion),
13332                                                                   fout);
13333                 }
13334         }
13335
13336         appendPQExpBufferStr(q, ");\n");
13337
13338         if (dopt->binary_upgrade)
13339                 binary_upgrade_extension_member(q, &collinfo->dobj,
13340                                                                                 "COLLATION", qcollname,
13341                                                                                 collinfo->dobj.namespace->dobj.name);
13342
13343         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13344                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13345                                          collinfo->dobj.name,
13346                                          collinfo->dobj.namespace->dobj.name,
13347                                          NULL,
13348                                          collinfo->rolname,
13349                                          "COLLATION", SECTION_PRE_DATA,
13350                                          q->data, delq->data, NULL,
13351                                          NULL, 0,
13352                                          NULL, NULL);
13353
13354         /* Dump Collation Comments */
13355         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13356                 dumpComment(fout, "COLLATION", qcollname,
13357                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13358                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13359
13360         PQclear(res);
13361
13362         destroyPQExpBuffer(query);
13363         destroyPQExpBuffer(q);
13364         destroyPQExpBuffer(delq);
13365         free(qcollname);
13366 }
13367
13368 /*
13369  * dumpConversion
13370  *        write out a single conversion definition
13371  */
13372 static void
13373 dumpConversion(Archive *fout, ConvInfo *convinfo)
13374 {
13375         DumpOptions *dopt = fout->dopt;
13376         PQExpBuffer query;
13377         PQExpBuffer q;
13378         PQExpBuffer delq;
13379         char       *qconvname;
13380         PGresult   *res;
13381         int                     i_conforencoding;
13382         int                     i_contoencoding;
13383         int                     i_conproc;
13384         int                     i_condefault;
13385         const char *conforencoding;
13386         const char *contoencoding;
13387         const char *conproc;
13388         bool            condefault;
13389
13390         /* Skip if not to be dumped */
13391         if (!convinfo->dobj.dump || dopt->dataOnly)
13392                 return;
13393
13394         query = createPQExpBuffer();
13395         q = createPQExpBuffer();
13396         delq = createPQExpBuffer();
13397
13398         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13399
13400         /* Get conversion-specific details */
13401         appendPQExpBuffer(query, "SELECT "
13402                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13403                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13404                                           "conproc, condefault "
13405                                           "FROM pg_catalog.pg_conversion c "
13406                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13407                                           convinfo->dobj.catId.oid);
13408
13409         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13410
13411         i_conforencoding = PQfnumber(res, "conforencoding");
13412         i_contoencoding = PQfnumber(res, "contoencoding");
13413         i_conproc = PQfnumber(res, "conproc");
13414         i_condefault = PQfnumber(res, "condefault");
13415
13416         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13417         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13418         conproc = PQgetvalue(res, 0, i_conproc);
13419         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13420
13421         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13422                                           fmtQualifiedDumpable(convinfo));
13423
13424         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13425                                           (condefault) ? "DEFAULT " : "",
13426                                           fmtQualifiedDumpable(convinfo));
13427         appendStringLiteralAH(q, conforencoding, fout);
13428         appendPQExpBufferStr(q, " TO ");
13429         appendStringLiteralAH(q, contoencoding, fout);
13430         /* regproc output is already sufficiently quoted */
13431         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13432
13433         if (dopt->binary_upgrade)
13434                 binary_upgrade_extension_member(q, &convinfo->dobj,
13435                                                                                 "CONVERSION", qconvname,
13436                                                                                 convinfo->dobj.namespace->dobj.name);
13437
13438         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13439                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13440                                          convinfo->dobj.name,
13441                                          convinfo->dobj.namespace->dobj.name,
13442                                          NULL,
13443                                          convinfo->rolname,
13444                                          "CONVERSION", SECTION_PRE_DATA,
13445                                          q->data, delq->data, NULL,
13446                                          NULL, 0,
13447                                          NULL, NULL);
13448
13449         /* Dump Conversion Comments */
13450         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13451                 dumpComment(fout, "CONVERSION", qconvname,
13452                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13453                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13454
13455         PQclear(res);
13456
13457         destroyPQExpBuffer(query);
13458         destroyPQExpBuffer(q);
13459         destroyPQExpBuffer(delq);
13460         free(qconvname);
13461 }
13462
13463 /*
13464  * format_aggregate_signature: generate aggregate name and argument list
13465  *
13466  * The argument type names are qualified if needed.  The aggregate name
13467  * is never qualified.
13468  */
13469 static char *
13470 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13471 {
13472         PQExpBufferData buf;
13473         int                     j;
13474
13475         initPQExpBuffer(&buf);
13476         if (honor_quotes)
13477                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13478         else
13479                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13480
13481         if (agginfo->aggfn.nargs == 0)
13482                 appendPQExpBuffer(&buf, "(*)");
13483         else
13484         {
13485                 appendPQExpBufferChar(&buf, '(');
13486                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13487                 {
13488                         char       *typname;
13489
13490                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13491                                                                                    zeroAsOpaque);
13492
13493                         appendPQExpBuffer(&buf, "%s%s",
13494                                                           (j > 0) ? ", " : "",
13495                                                           typname);
13496                         free(typname);
13497                 }
13498                 appendPQExpBufferChar(&buf, ')');
13499         }
13500         return buf.data;
13501 }
13502
13503 /*
13504  * dumpAgg
13505  *        write out a single aggregate definition
13506  */
13507 static void
13508 dumpAgg(Archive *fout, AggInfo *agginfo)
13509 {
13510         DumpOptions *dopt = fout->dopt;
13511         PQExpBuffer query;
13512         PQExpBuffer q;
13513         PQExpBuffer delq;
13514         PQExpBuffer details;
13515         char       *aggsig;                     /* identity signature */
13516         char       *aggfullsig = NULL;  /* full signature */
13517         char       *aggsig_tag;
13518         PGresult   *res;
13519         int                     i_aggtransfn;
13520         int                     i_aggfinalfn;
13521         int                     i_aggcombinefn;
13522         int                     i_aggserialfn;
13523         int                     i_aggdeserialfn;
13524         int                     i_aggmtransfn;
13525         int                     i_aggminvtransfn;
13526         int                     i_aggmfinalfn;
13527         int                     i_aggfinalextra;
13528         int                     i_aggmfinalextra;
13529         int                     i_aggfinalmodify;
13530         int                     i_aggmfinalmodify;
13531         int                     i_aggsortop;
13532         int                     i_aggkind;
13533         int                     i_aggtranstype;
13534         int                     i_aggtransspace;
13535         int                     i_aggmtranstype;
13536         int                     i_aggmtransspace;
13537         int                     i_agginitval;
13538         int                     i_aggminitval;
13539         int                     i_convertok;
13540         int                     i_proparallel;
13541         const char *aggtransfn;
13542         const char *aggfinalfn;
13543         const char *aggcombinefn;
13544         const char *aggserialfn;
13545         const char *aggdeserialfn;
13546         const char *aggmtransfn;
13547         const char *aggminvtransfn;
13548         const char *aggmfinalfn;
13549         bool            aggfinalextra;
13550         bool            aggmfinalextra;
13551         char            aggfinalmodify;
13552         char            aggmfinalmodify;
13553         const char *aggsortop;
13554         char       *aggsortconvop;
13555         char            aggkind;
13556         const char *aggtranstype;
13557         const char *aggtransspace;
13558         const char *aggmtranstype;
13559         const char *aggmtransspace;
13560         const char *agginitval;
13561         const char *aggminitval;
13562         bool            convertok;
13563         const char *proparallel;
13564         char            defaultfinalmodify;
13565
13566         /* Skip if not to be dumped */
13567         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13568                 return;
13569
13570         query = createPQExpBuffer();
13571         q = createPQExpBuffer();
13572         delq = createPQExpBuffer();
13573         details = createPQExpBuffer();
13574
13575         /* Get aggregate-specific details */
13576         if (fout->remoteVersion >= 110000)
13577         {
13578                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13579                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13580                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13581                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13582                                                   "aggfinalextra, aggmfinalextra, "
13583                                                   "aggfinalmodify, aggmfinalmodify, "
13584                                                   "aggsortop, "
13585                                                   "aggkind, "
13586                                                   "aggtransspace, agginitval, "
13587                                                   "aggmtransspace, aggminitval, "
13588                                                   "true AS convertok, "
13589                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13590                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13591                                                   "p.proparallel "
13592                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13593                                                   "WHERE a.aggfnoid = p.oid "
13594                                                   "AND p.oid = '%u'::pg_catalog.oid",
13595                                                   agginfo->aggfn.dobj.catId.oid);
13596         }
13597         else if (fout->remoteVersion >= 90600)
13598         {
13599                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13600                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13601                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13602                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13603                                                   "aggfinalextra, aggmfinalextra, "
13604                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13605                                                   "aggsortop, "
13606                                                   "aggkind, "
13607                                                   "aggtransspace, agginitval, "
13608                                                   "aggmtransspace, aggminitval, "
13609                                                   "true AS convertok, "
13610                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13611                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13612                                                   "p.proparallel "
13613                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13614                                                   "WHERE a.aggfnoid = p.oid "
13615                                                   "AND p.oid = '%u'::pg_catalog.oid",
13616                                                   agginfo->aggfn.dobj.catId.oid);
13617         }
13618         else if (fout->remoteVersion >= 90400)
13619         {
13620                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13621                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13622                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13623                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13624                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13625                                                   "aggfinalextra, aggmfinalextra, "
13626                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13627                                                   "aggsortop, "
13628                                                   "aggkind, "
13629                                                   "aggtransspace, agginitval, "
13630                                                   "aggmtransspace, aggminitval, "
13631                                                   "true AS convertok, "
13632                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13633                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13634                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13635                                                   "WHERE a.aggfnoid = p.oid "
13636                                                   "AND p.oid = '%u'::pg_catalog.oid",
13637                                                   agginfo->aggfn.dobj.catId.oid);
13638         }
13639         else if (fout->remoteVersion >= 80400)
13640         {
13641                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13642                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13643                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13644                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13645                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13646                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13647                                                   "false AS aggmfinalextra, "
13648                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13649                                                   "aggsortop, "
13650                                                   "'n' AS aggkind, "
13651                                                   "0 AS aggtransspace, agginitval, "
13652                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13653                                                   "true AS convertok, "
13654                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13655                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13656                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13657                                                   "WHERE a.aggfnoid = p.oid "
13658                                                   "AND p.oid = '%u'::pg_catalog.oid",
13659                                                   agginfo->aggfn.dobj.catId.oid);
13660         }
13661         else if (fout->remoteVersion >= 80100)
13662         {
13663                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13664                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13665                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13666                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13667                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13668                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13669                                                   "false AS aggmfinalextra, "
13670                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13671                                                   "aggsortop, "
13672                                                   "'n' AS aggkind, "
13673                                                   "0 AS aggtransspace, agginitval, "
13674                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13675                                                   "true AS convertok "
13676                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13677                                                   "WHERE a.aggfnoid = p.oid "
13678                                                   "AND p.oid = '%u'::pg_catalog.oid",
13679                                                   agginfo->aggfn.dobj.catId.oid);
13680         }
13681         else
13682         {
13683                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13684                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13685                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13686                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13687                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13688                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13689                                                   "false AS aggmfinalextra, "
13690                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13691                                                   "0 AS aggsortop, "
13692                                                   "'n' AS aggkind, "
13693                                                   "0 AS aggtransspace, agginitval, "
13694                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13695                                                   "true AS convertok "
13696                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13697                                                   "WHERE a.aggfnoid = p.oid "
13698                                                   "AND p.oid = '%u'::pg_catalog.oid",
13699                                                   agginfo->aggfn.dobj.catId.oid);
13700         }
13701
13702         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13703
13704         i_aggtransfn = PQfnumber(res, "aggtransfn");
13705         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13706         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13707         i_aggserialfn = PQfnumber(res, "aggserialfn");
13708         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13709         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13710         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13711         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13712         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13713         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13714         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13715         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13716         i_aggsortop = PQfnumber(res, "aggsortop");
13717         i_aggkind = PQfnumber(res, "aggkind");
13718         i_aggtranstype = PQfnumber(res, "aggtranstype");
13719         i_aggtransspace = PQfnumber(res, "aggtransspace");
13720         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13721         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13722         i_agginitval = PQfnumber(res, "agginitval");
13723         i_aggminitval = PQfnumber(res, "aggminitval");
13724         i_convertok = PQfnumber(res, "convertok");
13725         i_proparallel = PQfnumber(res, "proparallel");
13726
13727         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13728         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13729         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13730         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13731         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13732         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13733         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13734         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13735         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13736         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13737         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13738         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13739         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13740         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13741         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13742         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13743         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13744         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13745         agginitval = PQgetvalue(res, 0, i_agginitval);
13746         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13747         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13748
13749         if (fout->remoteVersion >= 80400)
13750         {
13751                 /* 8.4 or later; we rely on server-side code for most of the work */
13752                 char       *funcargs;
13753                 char       *funciargs;
13754
13755                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13756                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13757                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13758                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13759         }
13760         else
13761                 /* pre-8.4, do it ourselves */
13762                 aggsig = format_aggregate_signature(agginfo, fout, true);
13763
13764         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13765
13766         if (i_proparallel != -1)
13767                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13768         else
13769                 proparallel = NULL;
13770
13771         if (!convertok)
13772         {
13773                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13774                                   aggsig);
13775
13776                 if (aggfullsig)
13777                         free(aggfullsig);
13778
13779                 free(aggsig);
13780
13781                 return;
13782         }
13783
13784         /* identify default modify flag for aggkind (must match DefineAggregate) */
13785         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13786         /* replace omitted flags for old versions */
13787         if (aggfinalmodify == '0')
13788                 aggfinalmodify = defaultfinalmodify;
13789         if (aggmfinalmodify == '0')
13790                 aggmfinalmodify = defaultfinalmodify;
13791
13792         /* regproc and regtype output is already sufficiently quoted */
13793         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13794                                           aggtransfn, aggtranstype);
13795
13796         if (strcmp(aggtransspace, "0") != 0)
13797         {
13798                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13799                                                   aggtransspace);
13800         }
13801
13802         if (!PQgetisnull(res, 0, i_agginitval))
13803         {
13804                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13805                 appendStringLiteralAH(details, agginitval, fout);
13806         }
13807
13808         if (strcmp(aggfinalfn, "-") != 0)
13809         {
13810                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13811                                                   aggfinalfn);
13812                 if (aggfinalextra)
13813                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13814                 if (aggfinalmodify != defaultfinalmodify)
13815                 {
13816                         switch (aggfinalmodify)
13817                         {
13818                                 case AGGMODIFY_READ_ONLY:
13819                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13820                                         break;
13821                                 case AGGMODIFY_SHAREABLE:
13822                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
13823                                         break;
13824                                 case AGGMODIFY_READ_WRITE:
13825                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13826                                         break;
13827                                 default:
13828                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
13829                                                                   agginfo->aggfn.dobj.name);
13830                                         break;
13831                         }
13832                 }
13833         }
13834
13835         if (strcmp(aggcombinefn, "-") != 0)
13836                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13837
13838         if (strcmp(aggserialfn, "-") != 0)
13839                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13840
13841         if (strcmp(aggdeserialfn, "-") != 0)
13842                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13843
13844         if (strcmp(aggmtransfn, "-") != 0)
13845         {
13846                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13847                                                   aggmtransfn,
13848                                                   aggminvtransfn,
13849                                                   aggmtranstype);
13850         }
13851
13852         if (strcmp(aggmtransspace, "0") != 0)
13853         {
13854                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
13855                                                   aggmtransspace);
13856         }
13857
13858         if (!PQgetisnull(res, 0, i_aggminitval))
13859         {
13860                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
13861                 appendStringLiteralAH(details, aggminitval, fout);
13862         }
13863
13864         if (strcmp(aggmfinalfn, "-") != 0)
13865         {
13866                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
13867                                                   aggmfinalfn);
13868                 if (aggmfinalextra)
13869                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
13870                 if (aggmfinalmodify != defaultfinalmodify)
13871                 {
13872                         switch (aggmfinalmodify)
13873                         {
13874                                 case AGGMODIFY_READ_ONLY:
13875                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
13876                                         break;
13877                                 case AGGMODIFY_SHAREABLE:
13878                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
13879                                         break;
13880                                 case AGGMODIFY_READ_WRITE:
13881                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
13882                                         break;
13883                                 default:
13884                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
13885                                                                   agginfo->aggfn.dobj.name);
13886                                         break;
13887                         }
13888                 }
13889         }
13890
13891         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
13892         if (aggsortconvop)
13893         {
13894                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
13895                                                   aggsortconvop);
13896                 free(aggsortconvop);
13897         }
13898
13899         if (aggkind == AGGKIND_HYPOTHETICAL)
13900                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
13901
13902         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13903         {
13904                 if (proparallel[0] == PROPARALLEL_SAFE)
13905                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
13906                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13907                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
13908                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13909                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13910                                                   agginfo->aggfn.dobj.name);
13911         }
13912
13913         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13914                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13915                                           aggsig);
13916
13917         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
13918                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13919                                           aggfullsig ? aggfullsig : aggsig, details->data);
13920
13921         if (dopt->binary_upgrade)
13922                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
13923                                                                                 "AGGREGATE", aggsig,
13924                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
13925
13926         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13927                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13928                                          agginfo->aggfn.dobj.dumpId,
13929                                          aggsig_tag,
13930                                          agginfo->aggfn.dobj.namespace->dobj.name,
13931                                          NULL,
13932                                          agginfo->aggfn.rolname,
13933                                          "AGGREGATE", SECTION_PRE_DATA,
13934                                          q->data, delq->data, NULL,
13935                                          NULL, 0,
13936                                          NULL, NULL);
13937
13938         /* Dump Aggregate Comments */
13939         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13940                 dumpComment(fout, "AGGREGATE", aggsig,
13941                                         agginfo->aggfn.dobj.namespace->dobj.name,
13942                                         agginfo->aggfn.rolname,
13943                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13944
13945         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
13946                 dumpSecLabel(fout, "AGGREGATE", aggsig,
13947                                          agginfo->aggfn.dobj.namespace->dobj.name,
13948                                          agginfo->aggfn.rolname,
13949                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13950
13951         /*
13952          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
13953          * command look like a function's GRANT; in particular this affects the
13954          * syntax for zero-argument aggregates and ordered-set aggregates.
13955          */
13956         free(aggsig);
13957
13958         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
13959
13960         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
13961                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
13962                                 "FUNCTION", aggsig, NULL,
13963                                 agginfo->aggfn.dobj.namespace->dobj.name,
13964                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
13965                                 agginfo->aggfn.rproacl,
13966                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
13967
13968         free(aggsig);
13969         if (aggfullsig)
13970                 free(aggfullsig);
13971         free(aggsig_tag);
13972
13973         PQclear(res);
13974
13975         destroyPQExpBuffer(query);
13976         destroyPQExpBuffer(q);
13977         destroyPQExpBuffer(delq);
13978         destroyPQExpBuffer(details);
13979 }
13980
13981 /*
13982  * dumpTSParser
13983  *        write out a single text search parser
13984  */
13985 static void
13986 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
13987 {
13988         DumpOptions *dopt = fout->dopt;
13989         PQExpBuffer q;
13990         PQExpBuffer delq;
13991         char       *qprsname;
13992
13993         /* Skip if not to be dumped */
13994         if (!prsinfo->dobj.dump || dopt->dataOnly)
13995                 return;
13996
13997         q = createPQExpBuffer();
13998         delq = createPQExpBuffer();
13999
14000         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14001
14002         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14003                                           fmtQualifiedDumpable(prsinfo));
14004
14005         appendPQExpBuffer(q, "    START = %s,\n",
14006                                           convertTSFunction(fout, prsinfo->prsstart));
14007         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14008                                           convertTSFunction(fout, prsinfo->prstoken));
14009         appendPQExpBuffer(q, "    END = %s,\n",
14010                                           convertTSFunction(fout, prsinfo->prsend));
14011         if (prsinfo->prsheadline != InvalidOid)
14012                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14013                                                   convertTSFunction(fout, prsinfo->prsheadline));
14014         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14015                                           convertTSFunction(fout, prsinfo->prslextype));
14016
14017         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14018                                           fmtQualifiedDumpable(prsinfo));
14019
14020         if (dopt->binary_upgrade)
14021                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14022                                                                                 "TEXT SEARCH PARSER", qprsname,
14023                                                                                 prsinfo->dobj.namespace->dobj.name);
14024
14025         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14026                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14027                                          prsinfo->dobj.name,
14028                                          prsinfo->dobj.namespace->dobj.name,
14029                                          NULL,
14030                                          "",
14031                                          "TEXT SEARCH PARSER", SECTION_PRE_DATA,
14032                                          q->data, delq->data, NULL,
14033                                          NULL, 0,
14034                                          NULL, NULL);
14035
14036         /* Dump Parser Comments */
14037         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14038                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14039                                         prsinfo->dobj.namespace->dobj.name, "",
14040                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14041
14042         destroyPQExpBuffer(q);
14043         destroyPQExpBuffer(delq);
14044         free(qprsname);
14045 }
14046
14047 /*
14048  * dumpTSDictionary
14049  *        write out a single text search dictionary
14050  */
14051 static void
14052 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14053 {
14054         DumpOptions *dopt = fout->dopt;
14055         PQExpBuffer q;
14056         PQExpBuffer delq;
14057         PQExpBuffer query;
14058         char       *qdictname;
14059         PGresult   *res;
14060         char       *nspname;
14061         char       *tmplname;
14062
14063         /* Skip if not to be dumped */
14064         if (!dictinfo->dobj.dump || dopt->dataOnly)
14065                 return;
14066
14067         q = createPQExpBuffer();
14068         delq = createPQExpBuffer();
14069         query = createPQExpBuffer();
14070
14071         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14072
14073         /* Fetch name and namespace of the dictionary's template */
14074         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14075                                           "FROM pg_ts_template p, pg_namespace n "
14076                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14077                                           dictinfo->dicttemplate);
14078         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14079         nspname = PQgetvalue(res, 0, 0);
14080         tmplname = PQgetvalue(res, 0, 1);
14081
14082         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14083                                           fmtQualifiedDumpable(dictinfo));
14084
14085         appendPQExpBufferStr(q, "    TEMPLATE = ");
14086         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14087         appendPQExpBufferStr(q, fmtId(tmplname));
14088
14089         PQclear(res);
14090
14091         /* the dictinitoption can be dumped straight into the command */
14092         if (dictinfo->dictinitoption)
14093                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14094
14095         appendPQExpBufferStr(q, " );\n");
14096
14097         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14098                                           fmtQualifiedDumpable(dictinfo));
14099
14100         if (dopt->binary_upgrade)
14101                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14102                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14103                                                                                 dictinfo->dobj.namespace->dobj.name);
14104
14105         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14106                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14107                                          dictinfo->dobj.name,
14108                                          dictinfo->dobj.namespace->dobj.name,
14109                                          NULL,
14110                                          dictinfo->rolname,
14111                                          "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
14112                                          q->data, delq->data, NULL,
14113                                          NULL, 0,
14114                                          NULL, NULL);
14115
14116         /* Dump Dictionary Comments */
14117         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14118                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14119                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14120                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14121
14122         destroyPQExpBuffer(q);
14123         destroyPQExpBuffer(delq);
14124         destroyPQExpBuffer(query);
14125         free(qdictname);
14126 }
14127
14128 /*
14129  * dumpTSTemplate
14130  *        write out a single text search template
14131  */
14132 static void
14133 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14134 {
14135         DumpOptions *dopt = fout->dopt;
14136         PQExpBuffer q;
14137         PQExpBuffer delq;
14138         char       *qtmplname;
14139
14140         /* Skip if not to be dumped */
14141         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14142                 return;
14143
14144         q = createPQExpBuffer();
14145         delq = createPQExpBuffer();
14146
14147         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14148
14149         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14150                                           fmtQualifiedDumpable(tmplinfo));
14151
14152         if (tmplinfo->tmplinit != InvalidOid)
14153                 appendPQExpBuffer(q, "    INIT = %s,\n",
14154                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14155         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14156                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14157
14158         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14159                                           fmtQualifiedDumpable(tmplinfo));
14160
14161         if (dopt->binary_upgrade)
14162                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14163                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14164                                                                                 tmplinfo->dobj.namespace->dobj.name);
14165
14166         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14167                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14168                                          tmplinfo->dobj.name,
14169                                          tmplinfo->dobj.namespace->dobj.name,
14170                                          NULL,
14171                                          "",
14172                                          "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
14173                                          q->data, delq->data, NULL,
14174                                          NULL, 0,
14175                                          NULL, NULL);
14176
14177         /* Dump Template Comments */
14178         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14179                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14180                                         tmplinfo->dobj.namespace->dobj.name, "",
14181                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14182
14183         destroyPQExpBuffer(q);
14184         destroyPQExpBuffer(delq);
14185         free(qtmplname);
14186 }
14187
14188 /*
14189  * dumpTSConfig
14190  *        write out a single text search configuration
14191  */
14192 static void
14193 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14194 {
14195         DumpOptions *dopt = fout->dopt;
14196         PQExpBuffer q;
14197         PQExpBuffer delq;
14198         PQExpBuffer query;
14199         char       *qcfgname;
14200         PGresult   *res;
14201         char       *nspname;
14202         char       *prsname;
14203         int                     ntups,
14204                                 i;
14205         int                     i_tokenname;
14206         int                     i_dictname;
14207
14208         /* Skip if not to be dumped */
14209         if (!cfginfo->dobj.dump || dopt->dataOnly)
14210                 return;
14211
14212         q = createPQExpBuffer();
14213         delq = createPQExpBuffer();
14214         query = createPQExpBuffer();
14215
14216         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14217
14218         /* Fetch name and namespace of the config's parser */
14219         appendPQExpBuffer(query, "SELECT nspname, prsname "
14220                                           "FROM pg_ts_parser p, pg_namespace n "
14221                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14222                                           cfginfo->cfgparser);
14223         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14224         nspname = PQgetvalue(res, 0, 0);
14225         prsname = PQgetvalue(res, 0, 1);
14226
14227         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14228                                           fmtQualifiedDumpable(cfginfo));
14229
14230         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14231         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14232
14233         PQclear(res);
14234
14235         resetPQExpBuffer(query);
14236         appendPQExpBuffer(query,
14237                                           "SELECT\n"
14238                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14239                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14240                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14241                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14242                                           "WHERE m.mapcfg = '%u'\n"
14243                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14244                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14245
14246         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14247         ntups = PQntuples(res);
14248
14249         i_tokenname = PQfnumber(res, "tokenname");
14250         i_dictname = PQfnumber(res, "dictname");
14251
14252         for (i = 0; i < ntups; i++)
14253         {
14254                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14255                 char       *dictname = PQgetvalue(res, i, i_dictname);
14256
14257                 if (i == 0 ||
14258                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14259                 {
14260                         /* starting a new token type, so start a new command */
14261                         if (i > 0)
14262                                 appendPQExpBufferStr(q, ";\n");
14263                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14264                                                           fmtQualifiedDumpable(cfginfo));
14265                         /* tokenname needs quoting, dictname does NOT */
14266                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14267                                                           fmtId(tokenname), dictname);
14268                 }
14269                 else
14270                         appendPQExpBuffer(q, ", %s", dictname);
14271         }
14272
14273         if (ntups > 0)
14274                 appendPQExpBufferStr(q, ";\n");
14275
14276         PQclear(res);
14277
14278         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14279                                           fmtQualifiedDumpable(cfginfo));
14280
14281         if (dopt->binary_upgrade)
14282                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14283                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14284                                                                                 cfginfo->dobj.namespace->dobj.name);
14285
14286         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14287                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14288                                          cfginfo->dobj.name,
14289                                          cfginfo->dobj.namespace->dobj.name,
14290                                          NULL,
14291                                          cfginfo->rolname,
14292                                          "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14293                                          q->data, delq->data, NULL,
14294                                          NULL, 0,
14295                                          NULL, NULL);
14296
14297         /* Dump Configuration Comments */
14298         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14299                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14300                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14301                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14302
14303         destroyPQExpBuffer(q);
14304         destroyPQExpBuffer(delq);
14305         destroyPQExpBuffer(query);
14306         free(qcfgname);
14307 }
14308
14309 /*
14310  * dumpForeignDataWrapper
14311  *        write out a single foreign-data wrapper definition
14312  */
14313 static void
14314 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14315 {
14316         DumpOptions *dopt = fout->dopt;
14317         PQExpBuffer q;
14318         PQExpBuffer delq;
14319         char       *qfdwname;
14320
14321         /* Skip if not to be dumped */
14322         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14323                 return;
14324
14325         q = createPQExpBuffer();
14326         delq = createPQExpBuffer();
14327
14328         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14329
14330         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14331                                           qfdwname);
14332
14333         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14334                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14335
14336         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14337                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14338
14339         if (strlen(fdwinfo->fdwoptions) > 0)
14340                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14341
14342         appendPQExpBufferStr(q, ";\n");
14343
14344         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14345                                           qfdwname);
14346
14347         if (dopt->binary_upgrade)
14348                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14349                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14350                                                                                 NULL);
14351
14352         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14353                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14354                                          fdwinfo->dobj.name,
14355                                          NULL,
14356                                          NULL,
14357                                          fdwinfo->rolname,
14358                                          "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14359                                          q->data, delq->data, NULL,
14360                                          NULL, 0,
14361                                          NULL, NULL);
14362
14363         /* Dump Foreign Data Wrapper Comments */
14364         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14365                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14366                                         NULL, fdwinfo->rolname,
14367                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14368
14369         /* Handle the ACL */
14370         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14371                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14372                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14373                                 NULL, fdwinfo->rolname,
14374                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14375                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14376
14377         free(qfdwname);
14378
14379         destroyPQExpBuffer(q);
14380         destroyPQExpBuffer(delq);
14381 }
14382
14383 /*
14384  * dumpForeignServer
14385  *        write out a foreign server definition
14386  */
14387 static void
14388 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14389 {
14390         DumpOptions *dopt = fout->dopt;
14391         PQExpBuffer q;
14392         PQExpBuffer delq;
14393         PQExpBuffer query;
14394         PGresult   *res;
14395         char       *qsrvname;
14396         char       *fdwname;
14397
14398         /* Skip if not to be dumped */
14399         if (!srvinfo->dobj.dump || dopt->dataOnly)
14400                 return;
14401
14402         q = createPQExpBuffer();
14403         delq = createPQExpBuffer();
14404         query = createPQExpBuffer();
14405
14406         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14407
14408         /* look up the foreign-data wrapper */
14409         appendPQExpBuffer(query, "SELECT fdwname "
14410                                           "FROM pg_foreign_data_wrapper w "
14411                                           "WHERE w.oid = '%u'",
14412                                           srvinfo->srvfdw);
14413         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14414         fdwname = PQgetvalue(res, 0, 0);
14415
14416         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14417         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14418         {
14419                 appendPQExpBufferStr(q, " TYPE ");
14420                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14421         }
14422         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14423         {
14424                 appendPQExpBufferStr(q, " VERSION ");
14425                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14426         }
14427
14428         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14429         appendPQExpBufferStr(q, fmtId(fdwname));
14430
14431         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14432                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14433
14434         appendPQExpBufferStr(q, ";\n");
14435
14436         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14437                                           qsrvname);
14438
14439         if (dopt->binary_upgrade)
14440                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14441                                                                                 "SERVER", qsrvname, NULL);
14442
14443         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14444                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14445                                          srvinfo->dobj.name,
14446                                          NULL,
14447                                          NULL,
14448                                          srvinfo->rolname,
14449                                          "SERVER", SECTION_PRE_DATA,
14450                                          q->data, delq->data, NULL,
14451                                          NULL, 0,
14452                                          NULL, NULL);
14453
14454         /* Dump Foreign Server Comments */
14455         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14456                 dumpComment(fout, "SERVER", qsrvname,
14457                                         NULL, srvinfo->rolname,
14458                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14459
14460         /* Handle the ACL */
14461         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14462                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14463                                 "FOREIGN SERVER", qsrvname, NULL,
14464                                 NULL, srvinfo->rolname,
14465                                 srvinfo->srvacl, srvinfo->rsrvacl,
14466                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14467
14468         /* Dump user mappings */
14469         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14470                 dumpUserMappings(fout,
14471                                                  srvinfo->dobj.name, NULL,
14472                                                  srvinfo->rolname,
14473                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14474
14475         free(qsrvname);
14476
14477         destroyPQExpBuffer(q);
14478         destroyPQExpBuffer(delq);
14479         destroyPQExpBuffer(query);
14480 }
14481
14482 /*
14483  * dumpUserMappings
14484  *
14485  * This routine is used to dump any user mappings associated with the
14486  * server handed to this routine. Should be called after ArchiveEntry()
14487  * for the server.
14488  */
14489 static void
14490 dumpUserMappings(Archive *fout,
14491                                  const char *servername, const char *namespace,
14492                                  const char *owner,
14493                                  CatalogId catalogId, DumpId dumpId)
14494 {
14495         PQExpBuffer q;
14496         PQExpBuffer delq;
14497         PQExpBuffer query;
14498         PQExpBuffer tag;
14499         PGresult   *res;
14500         int                     ntups;
14501         int                     i_usename;
14502         int                     i_umoptions;
14503         int                     i;
14504
14505         q = createPQExpBuffer();
14506         tag = createPQExpBuffer();
14507         delq = createPQExpBuffer();
14508         query = createPQExpBuffer();
14509
14510         /*
14511          * We read from the publicly accessible view pg_user_mappings, so as not
14512          * to fail if run by a non-superuser.  Note that the view will show
14513          * umoptions as null if the user hasn't got privileges for the associated
14514          * server; this means that pg_dump will dump such a mapping, but with no
14515          * OPTIONS clause.  A possible alternative is to skip such mappings
14516          * altogether, but it's not clear that that's an improvement.
14517          */
14518         appendPQExpBuffer(query,
14519                                           "SELECT usename, "
14520                                           "array_to_string(ARRAY("
14521                                           "SELECT quote_ident(option_name) || ' ' || "
14522                                           "quote_literal(option_value) "
14523                                           "FROM pg_options_to_table(umoptions) "
14524                                           "ORDER BY option_name"
14525                                           "), E',\n    ') AS umoptions "
14526                                           "FROM pg_user_mappings "
14527                                           "WHERE srvid = '%u' "
14528                                           "ORDER BY usename",
14529                                           catalogId.oid);
14530
14531         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14532
14533         ntups = PQntuples(res);
14534         i_usename = PQfnumber(res, "usename");
14535         i_umoptions = PQfnumber(res, "umoptions");
14536
14537         for (i = 0; i < ntups; i++)
14538         {
14539                 char       *usename;
14540                 char       *umoptions;
14541
14542                 usename = PQgetvalue(res, i, i_usename);
14543                 umoptions = PQgetvalue(res, i, i_umoptions);
14544
14545                 resetPQExpBuffer(q);
14546                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14547                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14548
14549                 if (umoptions && strlen(umoptions) > 0)
14550                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14551
14552                 appendPQExpBufferStr(q, ";\n");
14553
14554                 resetPQExpBuffer(delq);
14555                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14556                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14557
14558                 resetPQExpBuffer(tag);
14559                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14560                                                   usename, servername);
14561
14562                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14563                                          tag->data,
14564                                          namespace,
14565                                          NULL,
14566                                          owner,
14567                                          "USER MAPPING", SECTION_PRE_DATA,
14568                                          q->data, delq->data, NULL,
14569                                          &dumpId, 1,
14570                                          NULL, NULL);
14571         }
14572
14573         PQclear(res);
14574
14575         destroyPQExpBuffer(query);
14576         destroyPQExpBuffer(delq);
14577         destroyPQExpBuffer(tag);
14578         destroyPQExpBuffer(q);
14579 }
14580
14581 /*
14582  * Write out default privileges information
14583  */
14584 static void
14585 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14586 {
14587         DumpOptions *dopt = fout->dopt;
14588         PQExpBuffer q;
14589         PQExpBuffer tag;
14590         const char *type;
14591
14592         /* Skip if not to be dumped */
14593         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14594                 return;
14595
14596         q = createPQExpBuffer();
14597         tag = createPQExpBuffer();
14598
14599         switch (daclinfo->defaclobjtype)
14600         {
14601                 case DEFACLOBJ_RELATION:
14602                         type = "TABLES";
14603                         break;
14604                 case DEFACLOBJ_SEQUENCE:
14605                         type = "SEQUENCES";
14606                         break;
14607                 case DEFACLOBJ_FUNCTION:
14608                         type = "FUNCTIONS";
14609                         break;
14610                 case DEFACLOBJ_TYPE:
14611                         type = "TYPES";
14612                         break;
14613                 case DEFACLOBJ_NAMESPACE:
14614                         type = "SCHEMAS";
14615                         break;
14616                 default:
14617                         /* shouldn't get here */
14618                         exit_horribly(NULL,
14619                                                   "unrecognized object type in default privileges: %d\n",
14620                                                   (int) daclinfo->defaclobjtype);
14621                         type = "";                      /* keep compiler quiet */
14622         }
14623
14624         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14625
14626         /* build the actual command(s) for this tuple */
14627         if (!buildDefaultACLCommands(type,
14628                                                                  daclinfo->dobj.namespace != NULL ?
14629                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14630                                                                  daclinfo->defaclacl,
14631                                                                  daclinfo->rdefaclacl,
14632                                                                  daclinfo->initdefaclacl,
14633                                                                  daclinfo->initrdefaclacl,
14634                                                                  daclinfo->defaclrole,
14635                                                                  fout->remoteVersion,
14636                                                                  q))
14637                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14638                                           daclinfo->defaclacl);
14639
14640         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14641                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14642                                          tag->data,
14643                                          daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14644                                          NULL,
14645                                          daclinfo->defaclrole,
14646                                          "DEFAULT ACL", SECTION_POST_DATA,
14647                                          q->data, "", NULL,
14648                                          NULL, 0,
14649                                          NULL, NULL);
14650
14651         destroyPQExpBuffer(tag);
14652         destroyPQExpBuffer(q);
14653 }
14654
14655 /*----------
14656  * Write out grant/revoke information
14657  *
14658  * 'objCatId' is the catalog ID of the underlying object.
14659  * 'objDumpId' is the dump ID of the underlying object.
14660  * 'type' must be one of
14661  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14662  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14663  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14664  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14665  *              (Currently we assume that subname is only provided for table columns.)
14666  * 'nspname' is the namespace the object is in (NULL if none).
14667  * 'owner' is the owner, NULL if there is no owner (for languages).
14668  * 'acls' contains the ACL string of the object from the appropriate system
14669  *              catalog field; it will be passed to buildACLCommands for building the
14670  *              appropriate GRANT commands.
14671  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14672  *              object; it will be passed to buildACLCommands for building the
14673  *              appropriate REVOKE commands.
14674  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14675  *              privileges, to be recorded into pg_init_privs
14676  * 'initracls' In binary-upgrade mode, ACL string of the object's
14677  *              revoked-from-default privileges, to be recorded into pg_init_privs
14678  *
14679  * NB: initacls/initracls are needed because extensions can set privileges on
14680  * an object during the extension's script file and we record those into
14681  * pg_init_privs as that object's initial privileges.
14682  *----------
14683  */
14684 static void
14685 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14686                 const char *type, const char *name, const char *subname,
14687                 const char *nspname, const char *owner,
14688                 const char *acls, const char *racls,
14689                 const char *initacls, const char *initracls)
14690 {
14691         DumpOptions *dopt = fout->dopt;
14692         PQExpBuffer sql;
14693
14694         /* Do nothing if ACL dump is not enabled */
14695         if (dopt->aclsSkip)
14696                 return;
14697
14698         /* --data-only skips ACLs *except* BLOB ACLs */
14699         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14700                 return;
14701
14702         sql = createPQExpBuffer();
14703
14704         /*
14705          * Check to see if this object has had any initial ACLs included for it.
14706          * If so, we are in binary upgrade mode and these are the ACLs to turn
14707          * into GRANT and REVOKE statements to set and record the initial
14708          * privileges for an extension object.  Let the backend know that these
14709          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14710          * before and after.
14711          */
14712         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14713         {
14714                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14715                 if (!buildACLCommands(name, subname, nspname, type,
14716                                                           initacls, initracls, owner,
14717                                                           "", fout->remoteVersion, sql))
14718                         exit_horribly(NULL,
14719                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14720                                                   initacls, initracls, name, type);
14721                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14722         }
14723
14724         if (!buildACLCommands(name, subname, nspname, type,
14725                                                   acls, racls, owner,
14726                                                   "", fout->remoteVersion, sql))
14727                 exit_horribly(NULL,
14728                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14729                                           acls, racls, name, type);
14730
14731         if (sql->len > 0)
14732         {
14733                 PQExpBuffer tag = createPQExpBuffer();
14734
14735                 if (subname)
14736                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14737                 else
14738                         appendPQExpBuffer(tag, "%s %s", type, name);
14739
14740                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14741                                          tag->data, nspname,
14742                                          NULL,
14743                                          owner ? owner : "",
14744                                          "ACL", SECTION_NONE,
14745                                          sql->data, "", NULL,
14746                                          &(objDumpId), 1,
14747                                          NULL, NULL);
14748                 destroyPQExpBuffer(tag);
14749         }
14750
14751         destroyPQExpBuffer(sql);
14752 }
14753
14754 /*
14755  * dumpSecLabel
14756  *
14757  * This routine is used to dump any security labels associated with the
14758  * object handed to this routine. The routine takes the object type
14759  * and object name (ready to print, except for schema decoration), plus
14760  * the namespace and owner of the object (for labeling the ArchiveEntry),
14761  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14762  * plus the dump ID for the object (for setting a dependency).
14763  * If a matching pg_seclabel entry is found, it is dumped.
14764  *
14765  * Note: although this routine takes a dumpId for dependency purposes,
14766  * that purpose is just to mark the dependency in the emitted dump file
14767  * for possible future use by pg_restore.  We do NOT use it for determining
14768  * ordering of the label in the dump file, because this routine is called
14769  * after dependency sorting occurs.  This routine should be called just after
14770  * calling ArchiveEntry() for the specified object.
14771  */
14772 static void
14773 dumpSecLabel(Archive *fout, const char *type, const char *name,
14774                          const char *namespace, const char *owner,
14775                          CatalogId catalogId, int subid, DumpId dumpId)
14776 {
14777         DumpOptions *dopt = fout->dopt;
14778         SecLabelItem *labels;
14779         int                     nlabels;
14780         int                     i;
14781         PQExpBuffer query;
14782
14783         /* do nothing, if --no-security-labels is supplied */
14784         if (dopt->no_security_labels)
14785                 return;
14786
14787         /* Security labels are schema not data ... except blob labels are data */
14788         if (strcmp(type, "LARGE OBJECT") != 0)
14789         {
14790                 if (dopt->dataOnly)
14791                         return;
14792         }
14793         else
14794         {
14795                 /* We do dump blob security labels in binary-upgrade mode */
14796                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14797                         return;
14798         }
14799
14800         /* Search for security labels associated with catalogId, using table */
14801         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14802
14803         query = createPQExpBuffer();
14804
14805         for (i = 0; i < nlabels; i++)
14806         {
14807                 /*
14808                  * Ignore label entries for which the subid doesn't match.
14809                  */
14810                 if (labels[i].objsubid != subid)
14811                         continue;
14812
14813                 appendPQExpBuffer(query,
14814                                                   "SECURITY LABEL FOR %s ON %s ",
14815                                                   fmtId(labels[i].provider), type);
14816                 if (namespace && *namespace)
14817                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14818                 appendPQExpBuffer(query, "%s IS ", name);
14819                 appendStringLiteralAH(query, labels[i].label, fout);
14820                 appendPQExpBufferStr(query, ";\n");
14821         }
14822
14823         if (query->len > 0)
14824         {
14825                 PQExpBuffer tag = createPQExpBuffer();
14826
14827                 appendPQExpBuffer(tag, "%s %s", type, name);
14828                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14829                                          tag->data, namespace, NULL, owner,
14830                                          "SECURITY LABEL", SECTION_NONE,
14831                                          query->data, "", NULL,
14832                                          &(dumpId), 1,
14833                                          NULL, NULL);
14834                 destroyPQExpBuffer(tag);
14835         }
14836
14837         destroyPQExpBuffer(query);
14838 }
14839
14840 /*
14841  * dumpTableSecLabel
14842  *
14843  * As above, but dump security label for both the specified table (or view)
14844  * and its columns.
14845  */
14846 static void
14847 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14848 {
14849         DumpOptions *dopt = fout->dopt;
14850         SecLabelItem *labels;
14851         int                     nlabels;
14852         int                     i;
14853         PQExpBuffer query;
14854         PQExpBuffer target;
14855
14856         /* do nothing, if --no-security-labels is supplied */
14857         if (dopt->no_security_labels)
14858                 return;
14859
14860         /* SecLabel are SCHEMA not data */
14861         if (dopt->dataOnly)
14862                 return;
14863
14864         /* Search for comments associated with relation, using table */
14865         nlabels = findSecLabels(fout,
14866                                                         tbinfo->dobj.catId.tableoid,
14867                                                         tbinfo->dobj.catId.oid,
14868                                                         &labels);
14869
14870         /* If security labels exist, build SECURITY LABEL statements */
14871         if (nlabels <= 0)
14872                 return;
14873
14874         query = createPQExpBuffer();
14875         target = createPQExpBuffer();
14876
14877         for (i = 0; i < nlabels; i++)
14878         {
14879                 const char *colname;
14880                 const char *provider = labels[i].provider;
14881                 const char *label = labels[i].label;
14882                 int                     objsubid = labels[i].objsubid;
14883
14884                 resetPQExpBuffer(target);
14885                 if (objsubid == 0)
14886                 {
14887                         appendPQExpBuffer(target, "%s %s", reltypename,
14888                                                           fmtQualifiedDumpable(tbinfo));
14889                 }
14890                 else
14891                 {
14892                         colname = getAttrName(objsubid, tbinfo);
14893                         /* first fmtXXX result must be consumed before calling again */
14894                         appendPQExpBuffer(target, "COLUMN %s",
14895                                                           fmtQualifiedDumpable(tbinfo));
14896                         appendPQExpBuffer(target, ".%s", fmtId(colname));
14897                 }
14898                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14899                                                   fmtId(provider), target->data);
14900                 appendStringLiteralAH(query, label, fout);
14901                 appendPQExpBufferStr(query, ";\n");
14902         }
14903         if (query->len > 0)
14904         {
14905                 resetPQExpBuffer(target);
14906                 appendPQExpBuffer(target, "%s %s", reltypename,
14907                                                   fmtId(tbinfo->dobj.name));
14908                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14909                                          target->data,
14910                                          tbinfo->dobj.namespace->dobj.name,
14911                                          NULL, tbinfo->rolname,
14912                                          "SECURITY LABEL", SECTION_NONE,
14913                                          query->data, "", NULL,
14914                                          &(tbinfo->dobj.dumpId), 1,
14915                                          NULL, NULL);
14916         }
14917         destroyPQExpBuffer(query);
14918         destroyPQExpBuffer(target);
14919 }
14920
14921 /*
14922  * findSecLabels
14923  *
14924  * Find the security label(s), if any, associated with the given object.
14925  * All the objsubid values associated with the given classoid/objoid are
14926  * found with one search.
14927  */
14928 static int
14929 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14930 {
14931         /* static storage for table of security labels */
14932         static SecLabelItem *labels = NULL;
14933         static int      nlabels = -1;
14934
14935         SecLabelItem *middle = NULL;
14936         SecLabelItem *low;
14937         SecLabelItem *high;
14938         int                     nmatch;
14939
14940         /* Get security labels if we didn't already */
14941         if (nlabels < 0)
14942                 nlabels = collectSecLabels(fout, &labels);
14943
14944         if (nlabels <= 0)                       /* no labels, so no match is possible */
14945         {
14946                 *items = NULL;
14947                 return 0;
14948         }
14949
14950         /*
14951          * Do binary search to find some item matching the object.
14952          */
14953         low = &labels[0];
14954         high = &labels[nlabels - 1];
14955         while (low <= high)
14956         {
14957                 middle = low + (high - low) / 2;
14958
14959                 if (classoid < middle->classoid)
14960                         high = middle - 1;
14961                 else if (classoid > middle->classoid)
14962                         low = middle + 1;
14963                 else if (objoid < middle->objoid)
14964                         high = middle - 1;
14965                 else if (objoid > middle->objoid)
14966                         low = middle + 1;
14967                 else
14968                         break;                          /* found a match */
14969         }
14970
14971         if (low > high)                         /* no matches */
14972         {
14973                 *items = NULL;
14974                 return 0;
14975         }
14976
14977         /*
14978          * Now determine how many items match the object.  The search loop
14979          * invariant still holds: only items between low and high inclusive could
14980          * match.
14981          */
14982         nmatch = 1;
14983         while (middle > low)
14984         {
14985                 if (classoid != middle[-1].classoid ||
14986                         objoid != middle[-1].objoid)
14987                         break;
14988                 middle--;
14989                 nmatch++;
14990         }
14991
14992         *items = middle;
14993
14994         middle += nmatch;
14995         while (middle <= high)
14996         {
14997                 if (classoid != middle->classoid ||
14998                         objoid != middle->objoid)
14999                         break;
15000                 middle++;
15001                 nmatch++;
15002         }
15003
15004         return nmatch;
15005 }
15006
15007 /*
15008  * collectSecLabels
15009  *
15010  * Construct a table of all security labels available for database objects.
15011  * It's much faster to pull them all at once.
15012  *
15013  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15014  */
15015 static int
15016 collectSecLabels(Archive *fout, SecLabelItem **items)
15017 {
15018         PGresult   *res;
15019         PQExpBuffer query;
15020         int                     i_label;
15021         int                     i_provider;
15022         int                     i_classoid;
15023         int                     i_objoid;
15024         int                     i_objsubid;
15025         int                     ntups;
15026         int                     i;
15027         SecLabelItem *labels;
15028
15029         query = createPQExpBuffer();
15030
15031         appendPQExpBufferStr(query,
15032                                                  "SELECT label, provider, classoid, objoid, objsubid "
15033                                                  "FROM pg_catalog.pg_seclabel "
15034                                                  "ORDER BY classoid, objoid, objsubid");
15035
15036         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15037
15038         /* Construct lookup table containing OIDs in numeric form */
15039         i_label = PQfnumber(res, "label");
15040         i_provider = PQfnumber(res, "provider");
15041         i_classoid = PQfnumber(res, "classoid");
15042         i_objoid = PQfnumber(res, "objoid");
15043         i_objsubid = PQfnumber(res, "objsubid");
15044
15045         ntups = PQntuples(res);
15046
15047         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15048
15049         for (i = 0; i < ntups; i++)
15050         {
15051                 labels[i].label = PQgetvalue(res, i, i_label);
15052                 labels[i].provider = PQgetvalue(res, i, i_provider);
15053                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15054                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15055                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15056         }
15057
15058         /* Do NOT free the PGresult since we are keeping pointers into it */
15059         destroyPQExpBuffer(query);
15060
15061         *items = labels;
15062         return ntups;
15063 }
15064
15065 /*
15066  * dumpTable
15067  *        write out to fout the declarations (not data) of a user-defined table
15068  */
15069 static void
15070 dumpTable(Archive *fout, TableInfo *tbinfo)
15071 {
15072         DumpOptions *dopt = fout->dopt;
15073         char       *namecopy;
15074
15075         /*
15076          * noop if we are not dumping anything about this table, or if we are
15077          * doing a data-only dump
15078          */
15079         if (!tbinfo->dobj.dump || dopt->dataOnly)
15080                 return;
15081
15082         if (tbinfo->relkind == RELKIND_SEQUENCE)
15083                 dumpSequence(fout, tbinfo);
15084         else
15085                 dumpTableSchema(fout, tbinfo);
15086
15087         /* Handle the ACL here */
15088         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15089         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15090         {
15091                 const char *objtype =
15092                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15093
15094                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15095                                 objtype, namecopy, NULL,
15096                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15097                                 tbinfo->relacl, tbinfo->rrelacl,
15098                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15099         }
15100
15101         /*
15102          * Handle column ACLs, if any.  Note: we pull these with a separate query
15103          * rather than trying to fetch them during getTableAttrs, so that we won't
15104          * miss ACLs on system columns.
15105          */
15106         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15107         {
15108                 PQExpBuffer query = createPQExpBuffer();
15109                 PGresult   *res;
15110                 int                     i;
15111
15112                 if (fout->remoteVersion >= 90600)
15113                 {
15114                         PQExpBuffer acl_subquery = createPQExpBuffer();
15115                         PQExpBuffer racl_subquery = createPQExpBuffer();
15116                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15117                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15118
15119                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15120                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15121                                                         dopt->binary_upgrade);
15122
15123                         appendPQExpBuffer(query,
15124                                                           "SELECT at.attname, "
15125                                                           "%s AS attacl, "
15126                                                           "%s AS rattacl, "
15127                                                           "%s AS initattacl, "
15128                                                           "%s AS initrattacl "
15129                                                           "FROM pg_catalog.pg_attribute at "
15130                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15131                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15132                                                           "(at.attrelid = pip.objoid "
15133                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15134                                                           "AND at.attnum = pip.objsubid) "
15135                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15136                                                           "NOT at.attisdropped "
15137                                                           "AND ("
15138                                                           "%s IS NOT NULL OR "
15139                                                           "%s IS NOT NULL OR "
15140                                                           "%s IS NOT NULL OR "
15141                                                           "%s IS NOT NULL)"
15142                                                           "ORDER BY at.attnum",
15143                                                           acl_subquery->data,
15144                                                           racl_subquery->data,
15145                                                           initacl_subquery->data,
15146                                                           initracl_subquery->data,
15147                                                           tbinfo->dobj.catId.oid,
15148                                                           acl_subquery->data,
15149                                                           racl_subquery->data,
15150                                                           initacl_subquery->data,
15151                                                           initracl_subquery->data);
15152
15153                         destroyPQExpBuffer(acl_subquery);
15154                         destroyPQExpBuffer(racl_subquery);
15155                         destroyPQExpBuffer(initacl_subquery);
15156                         destroyPQExpBuffer(initracl_subquery);
15157                 }
15158                 else
15159                 {
15160                         appendPQExpBuffer(query,
15161                                                           "SELECT attname, attacl, NULL as rattacl, "
15162                                                           "NULL AS initattacl, NULL AS initrattacl "
15163                                                           "FROM pg_catalog.pg_attribute "
15164                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15165                                                           "AND attacl IS NOT NULL "
15166                                                           "ORDER BY attnum",
15167                                                           tbinfo->dobj.catId.oid);
15168                 }
15169
15170                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15171
15172                 for (i = 0; i < PQntuples(res); i++)
15173                 {
15174                         char       *attname = PQgetvalue(res, i, 0);
15175                         char       *attacl = PQgetvalue(res, i, 1);
15176                         char       *rattacl = PQgetvalue(res, i, 2);
15177                         char       *initattacl = PQgetvalue(res, i, 3);
15178                         char       *initrattacl = PQgetvalue(res, i, 4);
15179                         char       *attnamecopy;
15180
15181                         attnamecopy = pg_strdup(fmtId(attname));
15182                         /* Column's GRANT type is always TABLE */
15183                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15184                                         "TABLE", namecopy, attnamecopy,
15185                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15186                                         attacl, rattacl, initattacl, initrattacl);
15187                         free(attnamecopy);
15188                 }
15189                 PQclear(res);
15190                 destroyPQExpBuffer(query);
15191         }
15192
15193         free(namecopy);
15194
15195         return;
15196 }
15197
15198 /*
15199  * Create the AS clause for a view or materialized view. The semicolon is
15200  * stripped because a materialized view must add a WITH NO DATA clause.
15201  *
15202  * This returns a new buffer which must be freed by the caller.
15203  */
15204 static PQExpBuffer
15205 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15206 {
15207         PQExpBuffer query = createPQExpBuffer();
15208         PQExpBuffer result = createPQExpBuffer();
15209         PGresult   *res;
15210         int                     len;
15211
15212         /* Fetch the view definition */
15213         appendPQExpBuffer(query,
15214                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15215                                           tbinfo->dobj.catId.oid);
15216
15217         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15218
15219         if (PQntuples(res) != 1)
15220         {
15221                 if (PQntuples(res) < 1)
15222                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15223                                                   tbinfo->dobj.name);
15224                 else
15225                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15226                                                   tbinfo->dobj.name);
15227         }
15228
15229         len = PQgetlength(res, 0, 0);
15230
15231         if (len == 0)
15232                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15233                                           tbinfo->dobj.name);
15234
15235         /* Strip off the trailing semicolon so that other things may follow. */
15236         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15237         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15238
15239         PQclear(res);
15240         destroyPQExpBuffer(query);
15241
15242         return result;
15243 }
15244
15245 /*
15246  * Create a dummy AS clause for a view.  This is used when the real view
15247  * definition has to be postponed because of circular dependencies.
15248  * We must duplicate the view's external properties -- column names and types
15249  * (including collation) -- so that it works for subsequent references.
15250  *
15251  * This returns a new buffer which must be freed by the caller.
15252  */
15253 static PQExpBuffer
15254 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15255 {
15256         PQExpBuffer result = createPQExpBuffer();
15257         int                     j;
15258
15259         appendPQExpBufferStr(result, "SELECT");
15260
15261         for (j = 0; j < tbinfo->numatts; j++)
15262         {
15263                 if (j > 0)
15264                         appendPQExpBufferChar(result, ',');
15265                 appendPQExpBufferStr(result, "\n    ");
15266
15267                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15268
15269                 /*
15270                  * Must add collation if not default for the type, because CREATE OR
15271                  * REPLACE VIEW won't change it
15272                  */
15273                 if (OidIsValid(tbinfo->attcollation[j]))
15274                 {
15275                         CollInfo   *coll;
15276
15277                         coll = findCollationByOid(tbinfo->attcollation[j]);
15278                         if (coll)
15279                                 appendPQExpBuffer(result, " COLLATE %s",
15280                                                                   fmtQualifiedDumpable(coll));
15281                 }
15282
15283                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15284         }
15285
15286         return result;
15287 }
15288
15289 /*
15290  * dumpTableSchema
15291  *        write the declaration (not data) of one user-defined table or view
15292  */
15293 static void
15294 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15295 {
15296         DumpOptions *dopt = fout->dopt;
15297         PQExpBuffer q = createPQExpBuffer();
15298         PQExpBuffer delq = createPQExpBuffer();
15299         char       *qrelname;
15300         char       *qualrelname;
15301         int                     numParents;
15302         TableInfo **parents;
15303         int                     actual_atts;    /* number of attrs in this CREATE statement */
15304         const char *reltypename;
15305         char       *storage;
15306         char       *srvname;
15307         char       *ftoptions;
15308         int                     j,
15309                                 k;
15310
15311         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15312         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15313
15314
15315         if (tbinfo->hasoids)
15316                 write_msg(NULL,
15317                                   "WARNING: WITH OIDS is not supported anymore (table \"%s\")\n",
15318                                   qrelname);
15319
15320         if (dopt->binary_upgrade)
15321                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15322                                                                                                 tbinfo->dobj.catId.oid);
15323
15324         /* Is it a table or a view? */
15325         if (tbinfo->relkind == RELKIND_VIEW)
15326         {
15327                 PQExpBuffer result;
15328
15329                 /*
15330                  * Note: keep this code in sync with the is_view case in dumpRule()
15331                  */
15332
15333                 reltypename = "VIEW";
15334
15335                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15336
15337                 if (dopt->binary_upgrade)
15338                         binary_upgrade_set_pg_class_oids(fout, q,
15339                                                                                          tbinfo->dobj.catId.oid, false);
15340
15341                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15342
15343                 if (tbinfo->dummy_view)
15344                         result = createDummyViewAsClause(fout, tbinfo);
15345                 else
15346                 {
15347                         if (nonemptyReloptions(tbinfo->reloptions))
15348                         {
15349                                 appendPQExpBufferStr(q, " WITH (");
15350                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15351                                 appendPQExpBufferChar(q, ')');
15352                         }
15353                         result = createViewAsClause(fout, tbinfo);
15354                 }
15355                 appendPQExpBuffer(q, " AS\n%s", result->data);
15356                 destroyPQExpBuffer(result);
15357
15358                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15359                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15360                 appendPQExpBufferStr(q, ";\n");
15361         }
15362         else
15363         {
15364                 switch (tbinfo->relkind)
15365                 {
15366                         case RELKIND_FOREIGN_TABLE:
15367                                 {
15368                                         PQExpBuffer query = createPQExpBuffer();
15369                                         PGresult   *res;
15370                                         int                     i_srvname;
15371                                         int                     i_ftoptions;
15372
15373                                         reltypename = "FOREIGN TABLE";
15374
15375                                         /* retrieve name of foreign server and generic options */
15376                                         appendPQExpBuffer(query,
15377                                                                           "SELECT fs.srvname, "
15378                                                                           "pg_catalog.array_to_string(ARRAY("
15379                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15380                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15381                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15382                                                                           "ORDER BY option_name"
15383                                                                           "), E',\n    ') AS ftoptions "
15384                                                                           "FROM pg_catalog.pg_foreign_table ft "
15385                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15386                                                                           "ON (fs.oid = ft.ftserver) "
15387                                                                           "WHERE ft.ftrelid = '%u'",
15388                                                                           tbinfo->dobj.catId.oid);
15389                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15390                                         i_srvname = PQfnumber(res, "srvname");
15391                                         i_ftoptions = PQfnumber(res, "ftoptions");
15392                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15393                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15394                                         PQclear(res);
15395                                         destroyPQExpBuffer(query);
15396                                         break;
15397                                 }
15398                         case RELKIND_MATVIEW:
15399                                 reltypename = "MATERIALIZED VIEW";
15400                                 srvname = NULL;
15401                                 ftoptions = NULL;
15402                                 break;
15403                         default:
15404                                 reltypename = "TABLE";
15405                                 srvname = NULL;
15406                                 ftoptions = NULL;
15407                 }
15408
15409                 numParents = tbinfo->numParents;
15410                 parents = tbinfo->parents;
15411
15412                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15413
15414                 if (dopt->binary_upgrade)
15415                         binary_upgrade_set_pg_class_oids(fout, q,
15416                                                                                          tbinfo->dobj.catId.oid, false);
15417
15418                 appendPQExpBuffer(q, "CREATE %s%s %s",
15419                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15420                                                   "UNLOGGED " : "",
15421                                                   reltypename,
15422                                                   qualrelname);
15423
15424                 /*
15425                  * Attach to type, if reloftype; except in case of a binary upgrade,
15426                  * we dump the table normally and attach it to the type afterward.
15427                  */
15428                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15429                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15430
15431                 /*
15432                  * If the table is a partition, dump it as such; except in the case of
15433                  * a binary upgrade, we dump the table normally and attach it to the
15434                  * parent afterward.
15435                  */
15436                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15437                 {
15438                         TableInfo  *parentRel = tbinfo->parents[0];
15439
15440                         /*
15441                          * With partitions, unlike inheritance, there can only be one
15442                          * parent.
15443                          */
15444                         if (tbinfo->numParents != 1)
15445                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15446                                                           tbinfo->numParents, tbinfo->dobj.name);
15447
15448                         appendPQExpBuffer(q, " PARTITION OF %s",
15449                                                           fmtQualifiedDumpable(parentRel));
15450                 }
15451
15452                 if (tbinfo->relkind != RELKIND_MATVIEW)
15453                 {
15454                         /* Dump the attributes */
15455                         actual_atts = 0;
15456                         for (j = 0; j < tbinfo->numatts; j++)
15457                         {
15458                                 /*
15459                                  * Normally, dump if it's locally defined in this table, and
15460                                  * not dropped.  But for binary upgrade, we'll dump all the
15461                                  * columns, and then fix up the dropped and nonlocal cases
15462                                  * below.
15463                                  */
15464                                 if (shouldPrintColumn(dopt, tbinfo, j))
15465                                 {
15466                                         /*
15467                                          * Default value --- suppress if to be printed separately.
15468                                          */
15469                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15470                                                                                            !tbinfo->attrdefs[j]->separate);
15471
15472                                         /*
15473                                          * Not Null constraint --- suppress if inherited, except
15474                                          * in binary-upgrade case where that won't work.
15475                                          */
15476                                         bool            has_notnull = (tbinfo->notnull[j] &&
15477                                                                                            (!tbinfo->inhNotNull[j] ||
15478                                                                                                 dopt->binary_upgrade));
15479
15480                                         /*
15481                                          * Skip column if fully defined by reloftype or the
15482                                          * partition parent.
15483                                          */
15484                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15485                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15486                                                 continue;
15487
15488                                         /* Format properly if not first attr */
15489                                         if (actual_atts == 0)
15490                                                 appendPQExpBufferStr(q, " (");
15491                                         else
15492                                                 appendPQExpBufferChar(q, ',');
15493                                         appendPQExpBufferStr(q, "\n    ");
15494                                         actual_atts++;
15495
15496                                         /* Attribute name */
15497                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15498
15499                                         if (tbinfo->attisdropped[j])
15500                                         {
15501                                                 /*
15502                                                  * ALTER TABLE DROP COLUMN clears
15503                                                  * pg_attribute.atttypid, so we will not have gotten a
15504                                                  * valid type name; insert INTEGER as a stopgap. We'll
15505                                                  * clean things up later.
15506                                                  */
15507                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15508                                                 /* Skip all the rest, too */
15509                                                 continue;
15510                                         }
15511
15512                                         /*
15513                                          * Attribute type
15514                                          *
15515                                          * In binary-upgrade mode, we always include the type. If
15516                                          * we aren't in binary-upgrade mode, then we skip the type
15517                                          * when creating a typed table ('OF type_name') or a
15518                                          * partition ('PARTITION OF'), since the type comes from
15519                                          * the parent/partitioned table.
15520                                          */
15521                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15522                                         {
15523                                                 appendPQExpBuffer(q, " %s",
15524                                                                                   tbinfo->atttypnames[j]);
15525                                         }
15526
15527                                         /* Add collation if not default for the type */
15528                                         if (OidIsValid(tbinfo->attcollation[j]))
15529                                         {
15530                                                 CollInfo   *coll;
15531
15532                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15533                                                 if (coll)
15534                                                         appendPQExpBuffer(q, " COLLATE %s",
15535                                                                                           fmtQualifiedDumpable(coll));
15536                                         }
15537
15538                                         if (has_default)
15539                                                 appendPQExpBuffer(q, " DEFAULT %s",
15540                                                                                   tbinfo->attrdefs[j]->adef_expr);
15541
15542                                         if (has_notnull)
15543                                                 appendPQExpBufferStr(q, " NOT NULL");
15544                                 }
15545                         }
15546
15547                         /*
15548                          * Add non-inherited CHECK constraints, if any.
15549                          */
15550                         for (j = 0; j < tbinfo->ncheck; j++)
15551                         {
15552                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15553
15554                                 if (constr->separate || !constr->conislocal)
15555                                         continue;
15556
15557                                 if (actual_atts == 0)
15558                                         appendPQExpBufferStr(q, " (\n    ");
15559                                 else
15560                                         appendPQExpBufferStr(q, ",\n    ");
15561
15562                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15563                                                                   fmtId(constr->dobj.name));
15564                                 appendPQExpBufferStr(q, constr->condef);
15565
15566                                 actual_atts++;
15567                         }
15568
15569                         if (actual_atts)
15570                                 appendPQExpBufferStr(q, "\n)");
15571                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15572                                            !dopt->binary_upgrade))
15573                         {
15574                                 /*
15575                                  * We must have a parenthesized attribute list, even though
15576                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15577                                  */
15578                                 appendPQExpBufferStr(q, " (\n)");
15579                         }
15580
15581                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15582                         {
15583                                 appendPQExpBufferChar(q, '\n');
15584                                 appendPQExpBufferStr(q, tbinfo->partbound);
15585                         }
15586
15587                         /* Emit the INHERITS clause, except if this is a partition. */
15588                         if (numParents > 0 &&
15589                                 !tbinfo->ispartition &&
15590                                 !dopt->binary_upgrade)
15591                         {
15592                                 appendPQExpBufferStr(q, "\nINHERITS (");
15593                                 for (k = 0; k < numParents; k++)
15594                                 {
15595                                         TableInfo  *parentRel = parents[k];
15596
15597                                         if (k > 0)
15598                                                 appendPQExpBufferStr(q, ", ");
15599                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15600                                 }
15601                                 appendPQExpBufferChar(q, ')');
15602                         }
15603
15604                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15605                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15606
15607                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15608                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15609                 }
15610
15611                 if (nonemptyReloptions(tbinfo->reloptions) ||
15612                         nonemptyReloptions(tbinfo->toast_reloptions))
15613                 {
15614                         bool            addcomma = false;
15615
15616                         appendPQExpBufferStr(q, "\nWITH (");
15617                         if (nonemptyReloptions(tbinfo->reloptions))
15618                         {
15619                                 addcomma = true;
15620                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15621                         }
15622                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15623                         {
15624                                 if (addcomma)
15625                                         appendPQExpBufferStr(q, ", ");
15626                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15627                                                                                 fout);
15628                         }
15629                         appendPQExpBufferChar(q, ')');
15630                 }
15631
15632                 /* Dump generic options if any */
15633                 if (ftoptions && ftoptions[0])
15634                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15635
15636                 /*
15637                  * For materialized views, create the AS clause just like a view. At
15638                  * this point, we always mark the view as not populated.
15639                  */
15640                 if (tbinfo->relkind == RELKIND_MATVIEW)
15641                 {
15642                         PQExpBuffer result;
15643
15644                         result = createViewAsClause(fout, tbinfo);
15645                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15646                                                           result->data);
15647                         destroyPQExpBuffer(result);
15648                 }
15649                 else
15650                         appendPQExpBufferStr(q, ";\n");
15651
15652                 /*
15653                  * in binary upgrade mode, update the catalog with any missing values
15654                  * that might be present.
15655                  */
15656                 if (dopt->binary_upgrade)
15657                 {
15658                         for (j = 0; j < tbinfo->numatts; j++)
15659                         {
15660                                 if (tbinfo->attmissingval[j][0] != '\0')
15661                                 {
15662                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15663                                         appendPQExpBufferStr(q,
15664                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15665                                         appendStringLiteralAH(q, qualrelname, fout);
15666                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15667                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15668                                         appendPQExpBufferStr(q, ",");
15669                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15670                                         appendPQExpBufferStr(q, ");\n\n");
15671                                 }
15672                         }
15673                 }
15674
15675                 /*
15676                  * To create binary-compatible heap files, we have to ensure the same
15677                  * physical column order, including dropped columns, as in the
15678                  * original.  Therefore, we create dropped columns above and drop them
15679                  * here, also updating their attlen/attalign values so that the
15680                  * dropped column can be skipped properly.  (We do not bother with
15681                  * restoring the original attbyval setting.)  Also, inheritance
15682                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15683                  * using an INHERITS clause --- the latter would possibly mess up the
15684                  * column order.  That also means we have to take care about setting
15685                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15686                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15687                  *
15688                  * We process foreign and partitioned tables here, even though they
15689                  * lack heap storage, because they can participate in inheritance
15690                  * relationships and we want this stuff to be consistent across the
15691                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15692                  * and matviews, even though they have storage, because we don't
15693                  * support altering or dropping columns in them, nor can they be part
15694                  * of inheritance trees.
15695                  */
15696                 if (dopt->binary_upgrade &&
15697                         (tbinfo->relkind == RELKIND_RELATION ||
15698                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15699                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15700                 {
15701                         for (j = 0; j < tbinfo->numatts; j++)
15702                         {
15703                                 if (tbinfo->attisdropped[j])
15704                                 {
15705                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15706                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15707                                                                           "SET attlen = %d, "
15708                                                                           "attalign = '%c', attbyval = false\n"
15709                                                                           "WHERE attname = ",
15710                                                                           tbinfo->attlen[j],
15711                                                                           tbinfo->attalign[j]);
15712                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15713                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15714                                         appendStringLiteralAH(q, qualrelname, fout);
15715                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15716
15717                                         if (tbinfo->relkind == RELKIND_RELATION ||
15718                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15719                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15720                                                                                   qualrelname);
15721                                         else
15722                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15723                                                                                   qualrelname);
15724                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15725                                                                           fmtId(tbinfo->attnames[j]));
15726                                 }
15727                                 else if (!tbinfo->attislocal[j])
15728                                 {
15729                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15730                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15731                                                                                  "SET attislocal = false\n"
15732                                                                                  "WHERE attname = ");
15733                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15734                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15735                                         appendStringLiteralAH(q, qualrelname, fout);
15736                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15737                                 }
15738                         }
15739
15740                         for (k = 0; k < tbinfo->ncheck; k++)
15741                         {
15742                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15743
15744                                 if (constr->separate || constr->conislocal)
15745                                         continue;
15746
15747                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15748                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15749                                                                   qualrelname);
15750                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15751                                                                   fmtId(constr->dobj.name));
15752                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15753                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15754                                                                          "SET conislocal = false\n"
15755                                                                          "WHERE contype = 'c' AND conname = ");
15756                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15757                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15758                                 appendStringLiteralAH(q, qualrelname, fout);
15759                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15760                         }
15761
15762                         if (numParents > 0)
15763                         {
15764                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15765                                 for (k = 0; k < numParents; k++)
15766                                 {
15767                                         TableInfo  *parentRel = parents[k];
15768
15769                                         /* In the partitioning case, we alter the parent */
15770                                         if (tbinfo->ispartition)
15771                                                 appendPQExpBuffer(q,
15772                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15773                                                                                   fmtQualifiedDumpable(parentRel));
15774                                         else
15775                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15776                                                                                   qualrelname);
15777
15778                                         /* Partition needs specifying the bounds */
15779                                         if (tbinfo->ispartition)
15780                                                 appendPQExpBuffer(q, "%s %s;\n",
15781                                                                                   qualrelname,
15782                                                                                   tbinfo->partbound);
15783                                         else
15784                                                 appendPQExpBuffer(q, "%s;\n",
15785                                                                                   fmtQualifiedDumpable(parentRel));
15786                                 }
15787                         }
15788
15789                         if (tbinfo->reloftype)
15790                         {
15791                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15792                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15793                                                                   qualrelname,
15794                                                                   tbinfo->reloftype);
15795                         }
15796                 }
15797
15798                 /*
15799                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15800                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15801                  * TOAST tables semi-independently, here we see them only as children
15802                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15803                  * child toast table is handled below.)
15804                  */
15805                 if (dopt->binary_upgrade &&
15806                         (tbinfo->relkind == RELKIND_RELATION ||
15807                          tbinfo->relkind == RELKIND_MATVIEW))
15808                 {
15809                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15810                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15811                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15812                                                           "WHERE oid = ",
15813                                                           tbinfo->frozenxid, tbinfo->minmxid);
15814                         appendStringLiteralAH(q, qualrelname, fout);
15815                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15816
15817                         if (tbinfo->toast_oid)
15818                         {
15819                                 /*
15820                                  * The toast table will have the same OID at restore, so we
15821                                  * can safely target it by OID.
15822                                  */
15823                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15824                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15825                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15826                                                                   "WHERE oid = '%u';\n",
15827                                                                   tbinfo->toast_frozenxid,
15828                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15829                         }
15830                 }
15831
15832                 /*
15833                  * In binary_upgrade mode, restore matviews' populated status by
15834                  * poking pg_class directly.  This is pretty ugly, but we can't use
15835                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15836                  * matview is not populated even though this matview is; in any case,
15837                  * we want to transfer the matview's heap storage, not run REFRESH.
15838                  */
15839                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15840                         tbinfo->relispopulated)
15841                 {
15842                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15843                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15844                                                                  "SET relispopulated = 't'\n"
15845                                                                  "WHERE oid = ");
15846                         appendStringLiteralAH(q, qualrelname, fout);
15847                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15848                 }
15849
15850                 /*
15851                  * Dump additional per-column properties that we can't handle in the
15852                  * main CREATE TABLE command.
15853                  */
15854                 for (j = 0; j < tbinfo->numatts; j++)
15855                 {
15856                         /* None of this applies to dropped columns */
15857                         if (tbinfo->attisdropped[j])
15858                                 continue;
15859
15860                         /*
15861                          * If we didn't dump the column definition explicitly above, and
15862                          * it is NOT NULL and did not inherit that property from a parent,
15863                          * we have to mark it separately.
15864                          */
15865                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
15866                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15867                         {
15868                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15869                                                                   qualrelname);
15870                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15871                                                                   fmtId(tbinfo->attnames[j]));
15872                         }
15873
15874                         /*
15875                          * Dump per-column statistics information. We only issue an ALTER
15876                          * TABLE statement if the attstattarget entry for this column is
15877                          * non-negative (i.e. it's not the default value)
15878                          */
15879                         if (tbinfo->attstattarget[j] >= 0)
15880                         {
15881                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15882                                                                   qualrelname);
15883                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15884                                                                   fmtId(tbinfo->attnames[j]));
15885                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15886                                                                   tbinfo->attstattarget[j]);
15887                         }
15888
15889                         /*
15890                          * Dump per-column storage information.  The statement is only
15891                          * dumped if the storage has been changed from the type's default.
15892                          */
15893                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15894                         {
15895                                 switch (tbinfo->attstorage[j])
15896                                 {
15897                                         case 'p':
15898                                                 storage = "PLAIN";
15899                                                 break;
15900                                         case 'e':
15901                                                 storage = "EXTERNAL";
15902                                                 break;
15903                                         case 'm':
15904                                                 storage = "MAIN";
15905                                                 break;
15906                                         case 'x':
15907                                                 storage = "EXTENDED";
15908                                                 break;
15909                                         default:
15910                                                 storage = NULL;
15911                                 }
15912
15913                                 /*
15914                                  * Only dump the statement if it's a storage type we recognize
15915                                  */
15916                                 if (storage != NULL)
15917                                 {
15918                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15919                                                                           qualrelname);
15920                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
15921                                                                           fmtId(tbinfo->attnames[j]));
15922                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
15923                                                                           storage);
15924                                 }
15925                         }
15926
15927                         /*
15928                          * Dump per-column attributes.
15929                          */
15930                         if (tbinfo->attoptions[j][0] != '\0')
15931                         {
15932                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15933                                                                   qualrelname);
15934                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15935                                                                   fmtId(tbinfo->attnames[j]));
15936                                 appendPQExpBuffer(q, "SET (%s);\n",
15937                                                                   tbinfo->attoptions[j]);
15938                         }
15939
15940                         /*
15941                          * Dump per-column fdw options.
15942                          */
15943                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15944                                 tbinfo->attfdwoptions[j][0] != '\0')
15945                         {
15946                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
15947                                                                   qualrelname);
15948                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15949                                                                   fmtId(tbinfo->attnames[j]));
15950                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
15951                                                                   tbinfo->attfdwoptions[j]);
15952                         }
15953                 }
15954         }
15955
15956         /*
15957          * dump properties we only have ALTER TABLE syntax for
15958          */
15959         if ((tbinfo->relkind == RELKIND_RELATION ||
15960                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
15961                  tbinfo->relkind == RELKIND_MATVIEW) &&
15962                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
15963         {
15964                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
15965                 {
15966                         /* nothing to do, will be set when the index is dumped */
15967                 }
15968                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
15969                 {
15970                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
15971                                                           qualrelname);
15972                 }
15973                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
15974                 {
15975                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
15976                                                           qualrelname);
15977                 }
15978         }
15979
15980         if (tbinfo->forcerowsec)
15981                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
15982                                                   qualrelname);
15983
15984         if (dopt->binary_upgrade)
15985                 binary_upgrade_extension_member(q, &tbinfo->dobj,
15986                                                                                 reltypename, qrelname,
15987                                                                                 tbinfo->dobj.namespace->dobj.name);
15988
15989         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15990                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15991                                          tbinfo->dobj.name,
15992                                          tbinfo->dobj.namespace->dobj.name,
15993                                          (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
15994                                          tbinfo->rolname,
15995                                          reltypename,
15996                                          tbinfo->postponed_def ?
15997                                          SECTION_POST_DATA : SECTION_PRE_DATA,
15998                                          q->data, delq->data, NULL,
15999                                          NULL, 0,
16000                                          NULL, NULL);
16001
16002
16003         /* Dump Table Comments */
16004         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16005                 dumpTableComment(fout, tbinfo, reltypename);
16006
16007         /* Dump Table Security Labels */
16008         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16009                 dumpTableSecLabel(fout, tbinfo, reltypename);
16010
16011         /* Dump comments on inlined table constraints */
16012         for (j = 0; j < tbinfo->ncheck; j++)
16013         {
16014                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16015
16016                 if (constr->separate || !constr->conislocal)
16017                         continue;
16018
16019                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16020                         dumpTableConstraintComment(fout, constr);
16021         }
16022
16023         destroyPQExpBuffer(q);
16024         destroyPQExpBuffer(delq);
16025         free(qrelname);
16026         free(qualrelname);
16027 }
16028
16029 /*
16030  * dumpAttrDef --- dump an attribute's default-value declaration
16031  */
16032 static void
16033 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16034 {
16035         DumpOptions *dopt = fout->dopt;
16036         TableInfo  *tbinfo = adinfo->adtable;
16037         int                     adnum = adinfo->adnum;
16038         PQExpBuffer q;
16039         PQExpBuffer delq;
16040         char       *qualrelname;
16041         char       *tag;
16042
16043         /* Skip if table definition not to be dumped */
16044         if (!tbinfo->dobj.dump || dopt->dataOnly)
16045                 return;
16046
16047         /* Skip if not "separate"; it was dumped in the table's definition */
16048         if (!adinfo->separate)
16049                 return;
16050
16051         q = createPQExpBuffer();
16052         delq = createPQExpBuffer();
16053
16054         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16055
16056         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16057                                           qualrelname);
16058         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16059                                           fmtId(tbinfo->attnames[adnum - 1]),
16060                                           adinfo->adef_expr);
16061
16062         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16063                                           qualrelname);
16064         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16065                                           fmtId(tbinfo->attnames[adnum - 1]));
16066
16067         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16068
16069         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16070                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16071                                          tag,
16072                                          tbinfo->dobj.namespace->dobj.name,
16073                                          NULL,
16074                                          tbinfo->rolname,
16075                                          "DEFAULT", SECTION_PRE_DATA,
16076                                          q->data, delq->data, NULL,
16077                                          NULL, 0,
16078                                          NULL, NULL);
16079
16080         free(tag);
16081         destroyPQExpBuffer(q);
16082         destroyPQExpBuffer(delq);
16083         free(qualrelname);
16084 }
16085
16086 /*
16087  * getAttrName: extract the correct name for an attribute
16088  *
16089  * The array tblInfo->attnames[] only provides names of user attributes;
16090  * if a system attribute number is supplied, we have to fake it.
16091  * We also do a little bit of bounds checking for safety's sake.
16092  */
16093 static const char *
16094 getAttrName(int attrnum, TableInfo *tblInfo)
16095 {
16096         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16097                 return tblInfo->attnames[attrnum - 1];
16098         switch (attrnum)
16099         {
16100                 case SelfItemPointerAttributeNumber:
16101                         return "ctid";
16102                 case MinTransactionIdAttributeNumber:
16103                         return "xmin";
16104                 case MinCommandIdAttributeNumber:
16105                         return "cmin";
16106                 case MaxTransactionIdAttributeNumber:
16107                         return "xmax";
16108                 case MaxCommandIdAttributeNumber:
16109                         return "cmax";
16110                 case TableOidAttributeNumber:
16111                         return "tableoid";
16112         }
16113         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16114                                   attrnum, tblInfo->dobj.name);
16115         return NULL;                            /* keep compiler quiet */
16116 }
16117
16118 /*
16119  * dumpIndex
16120  *        write out to fout a user-defined index
16121  */
16122 static void
16123 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16124 {
16125         DumpOptions *dopt = fout->dopt;
16126         TableInfo  *tbinfo = indxinfo->indextable;
16127         bool            is_constraint = (indxinfo->indexconstraint != 0);
16128         PQExpBuffer q;
16129         PQExpBuffer delq;
16130         char       *qindxname;
16131
16132         if (dopt->dataOnly)
16133                 return;
16134
16135         q = createPQExpBuffer();
16136         delq = createPQExpBuffer();
16137
16138         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16139
16140         /*
16141          * If there's an associated constraint, don't dump the index per se, but
16142          * do dump any comment for it.  (This is safe because dependency ordering
16143          * will have ensured the constraint is emitted first.)  Note that the
16144          * emitted comment has to be shown as depending on the constraint, not the
16145          * index, in such cases.
16146          */
16147         if (!is_constraint)
16148         {
16149                 if (dopt->binary_upgrade)
16150                         binary_upgrade_set_pg_class_oids(fout, q,
16151                                                                                          indxinfo->dobj.catId.oid, true);
16152
16153                 /* Plain secondary index */
16154                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16155
16156                 /*
16157                  * Append ALTER TABLE commands as needed to set properties that we
16158                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16159                  * similar code in dumpConstraint!
16160                  */
16161
16162                 /* If the index is clustered, we need to record that. */
16163                 if (indxinfo->indisclustered)
16164                 {
16165                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16166                                                           fmtQualifiedDumpable(tbinfo));
16167                         /* index name is not qualified in this syntax */
16168                         appendPQExpBuffer(q, " ON %s;\n",
16169                                                           qindxname);
16170                 }
16171
16172                 /* If the index defines identity, we need to record that. */
16173                 if (indxinfo->indisreplident)
16174                 {
16175                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16176                                                           fmtQualifiedDumpable(tbinfo));
16177                         /* index name is not qualified in this syntax */
16178                         appendPQExpBuffer(q, " INDEX %s;\n",
16179                                                           qindxname);
16180                 }
16181
16182                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16183                                                   fmtQualifiedDumpable(indxinfo));
16184
16185                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16186                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16187                                                  indxinfo->dobj.name,
16188                                                  tbinfo->dobj.namespace->dobj.name,
16189                                                  indxinfo->tablespace,
16190                                                  tbinfo->rolname,
16191                                                  "INDEX", SECTION_POST_DATA,
16192                                                  q->data, delq->data, NULL,
16193                                                  NULL, 0,
16194                                                  NULL, NULL);
16195         }
16196
16197         /* Dump Index Comments */
16198         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16199                 dumpComment(fout, "INDEX", qindxname,
16200                                         tbinfo->dobj.namespace->dobj.name,
16201                                         tbinfo->rolname,
16202                                         indxinfo->dobj.catId, 0,
16203                                         is_constraint ? indxinfo->indexconstraint :
16204                                         indxinfo->dobj.dumpId);
16205
16206         destroyPQExpBuffer(q);
16207         destroyPQExpBuffer(delq);
16208         free(qindxname);
16209 }
16210
16211 /*
16212  * dumpIndexAttach
16213  *        write out to fout a partitioned-index attachment clause
16214  */
16215 static void
16216 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16217 {
16218         if (fout->dopt->dataOnly)
16219                 return;
16220
16221         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16222         {
16223                 PQExpBuffer q = createPQExpBuffer();
16224
16225                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16226                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16227                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16228                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16229
16230                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16231                                          attachinfo->dobj.name,
16232                                          attachinfo->dobj.namespace->dobj.name,
16233                                          NULL,
16234                                          "",
16235                                          "INDEX ATTACH", SECTION_POST_DATA,
16236                                          q->data, "", NULL,
16237                                          NULL, 0,
16238                                          NULL, NULL);
16239
16240                 destroyPQExpBuffer(q);
16241         }
16242 }
16243
16244 /*
16245  * dumpStatisticsExt
16246  *        write out to fout an extended statistics object
16247  */
16248 static void
16249 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16250 {
16251         DumpOptions *dopt = fout->dopt;
16252         PQExpBuffer q;
16253         PQExpBuffer delq;
16254         PQExpBuffer query;
16255         char       *qstatsextname;
16256         PGresult   *res;
16257         char       *stxdef;
16258
16259         /* Skip if not to be dumped */
16260         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16261                 return;
16262
16263         q = createPQExpBuffer();
16264         delq = createPQExpBuffer();
16265         query = createPQExpBuffer();
16266
16267         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16268
16269         appendPQExpBuffer(query, "SELECT "
16270                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16271                                           statsextinfo->dobj.catId.oid);
16272
16273         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16274
16275         stxdef = PQgetvalue(res, 0, 0);
16276
16277         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16278         appendPQExpBuffer(q, "%s;\n", stxdef);
16279
16280         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16281                                           fmtQualifiedDumpable(statsextinfo));
16282
16283         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16284                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16285                                          statsextinfo->dobj.dumpId,
16286                                          statsextinfo->dobj.name,
16287                                          statsextinfo->dobj.namespace->dobj.name,
16288                                          NULL,
16289                                          statsextinfo->rolname,
16290                                          "STATISTICS", SECTION_POST_DATA,
16291                                          q->data, delq->data, NULL,
16292                                          NULL, 0,
16293                                          NULL, NULL);
16294
16295         /* Dump Statistics Comments */
16296         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16297                 dumpComment(fout, "STATISTICS", qstatsextname,
16298                                         statsextinfo->dobj.namespace->dobj.name,
16299                                         statsextinfo->rolname,
16300                                         statsextinfo->dobj.catId, 0,
16301                                         statsextinfo->dobj.dumpId);
16302
16303         PQclear(res);
16304         destroyPQExpBuffer(q);
16305         destroyPQExpBuffer(delq);
16306         destroyPQExpBuffer(query);
16307         free(qstatsextname);
16308 }
16309
16310 /*
16311  * dumpConstraint
16312  *        write out to fout a user-defined constraint
16313  */
16314 static void
16315 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16316 {
16317         DumpOptions *dopt = fout->dopt;
16318         TableInfo  *tbinfo = coninfo->contable;
16319         PQExpBuffer q;
16320         PQExpBuffer delq;
16321         char       *tag = NULL;
16322
16323         /* Skip if not to be dumped */
16324         if (!coninfo->dobj.dump || dopt->dataOnly)
16325                 return;
16326
16327         q = createPQExpBuffer();
16328         delq = createPQExpBuffer();
16329
16330         if (coninfo->contype == 'p' ||
16331                 coninfo->contype == 'u' ||
16332                 coninfo->contype == 'x')
16333         {
16334                 /* Index-related constraint */
16335                 IndxInfo   *indxinfo;
16336                 int                     k;
16337
16338                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16339
16340                 if (indxinfo == NULL)
16341                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16342                                                   coninfo->dobj.name);
16343
16344                 if (dopt->binary_upgrade)
16345                         binary_upgrade_set_pg_class_oids(fout, q,
16346                                                                                          indxinfo->dobj.catId.oid, true);
16347
16348                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16349                                                   fmtQualifiedDumpable(tbinfo));
16350                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16351                                                   fmtId(coninfo->dobj.name));
16352
16353                 if (coninfo->condef)
16354                 {
16355                         /* pg_get_constraintdef should have provided everything */
16356                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16357                 }
16358                 else
16359                 {
16360                         appendPQExpBuffer(q, "%s (",
16361                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16362                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16363                         {
16364                                 int                     indkey = (int) indxinfo->indkeys[k];
16365                                 const char *attname;
16366
16367                                 if (indkey == InvalidAttrNumber)
16368                                         break;
16369                                 attname = getAttrName(indkey, tbinfo);
16370
16371                                 appendPQExpBuffer(q, "%s%s",
16372                                                                   (k == 0) ? "" : ", ",
16373                                                                   fmtId(attname));
16374                         }
16375
16376                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16377                                 appendPQExpBuffer(q, ") INCLUDE (");
16378
16379                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16380                         {
16381                                 int                     indkey = (int) indxinfo->indkeys[k];
16382                                 const char *attname;
16383
16384                                 if (indkey == InvalidAttrNumber)
16385                                         break;
16386                                 attname = getAttrName(indkey, tbinfo);
16387
16388                                 appendPQExpBuffer(q, "%s%s",
16389                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16390                                                                   fmtId(attname));
16391                         }
16392
16393                         appendPQExpBufferChar(q, ')');
16394
16395                         if (nonemptyReloptions(indxinfo->indreloptions))
16396                         {
16397                                 appendPQExpBufferStr(q, " WITH (");
16398                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16399                                 appendPQExpBufferChar(q, ')');
16400                         }
16401
16402                         if (coninfo->condeferrable)
16403                         {
16404                                 appendPQExpBufferStr(q, " DEFERRABLE");
16405                                 if (coninfo->condeferred)
16406                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16407                         }
16408
16409                         appendPQExpBufferStr(q, ";\n");
16410                 }
16411
16412                 /*
16413                  * Append ALTER TABLE commands as needed to set properties that we
16414                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16415                  * similar code in dumpIndex!
16416                  */
16417
16418                 /* If the index is clustered, we need to record that. */
16419                 if (indxinfo->indisclustered)
16420                 {
16421                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16422                                                           fmtQualifiedDumpable(tbinfo));
16423                         /* index name is not qualified in this syntax */
16424                         appendPQExpBuffer(q, " ON %s;\n",
16425                                                           fmtId(indxinfo->dobj.name));
16426                 }
16427
16428                 /* If the index defines identity, we need to record that. */
16429                 if (indxinfo->indisreplident)
16430                 {
16431                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16432                                                           fmtQualifiedDumpable(tbinfo));
16433                         /* index name is not qualified in this syntax */
16434                         appendPQExpBuffer(q, " INDEX %s;\n",
16435                                                           fmtId(indxinfo->dobj.name));
16436                 }
16437
16438                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16439                                                   fmtQualifiedDumpable(tbinfo));
16440                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16441                                                   fmtId(coninfo->dobj.name));
16442
16443                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16444
16445                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16446                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16447                                                  tag,
16448                                                  tbinfo->dobj.namespace->dobj.name,
16449                                                  indxinfo->tablespace,
16450                                                  tbinfo->rolname,
16451                                                  "CONSTRAINT", SECTION_POST_DATA,
16452                                                  q->data, delq->data, NULL,
16453                                                  NULL, 0,
16454                                                  NULL, NULL);
16455         }
16456         else if (coninfo->contype == 'f')
16457         {
16458                 char       *only;
16459
16460                 /*
16461                  * Foreign keys on partitioned tables are always declared as
16462                  * inheriting to partitions; for all other cases, emit them as
16463                  * applying ONLY directly to the named table, because that's how they
16464                  * work for regular inherited tables.
16465                  */
16466                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16467
16468                 /*
16469                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16470                  * current table data is not processed
16471                  */
16472                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16473                                                   only, fmtQualifiedDumpable(tbinfo));
16474                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16475                                                   fmtId(coninfo->dobj.name),
16476                                                   coninfo->condef);
16477
16478                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16479                                                   only, fmtQualifiedDumpable(tbinfo));
16480                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16481                                                   fmtId(coninfo->dobj.name));
16482
16483                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16484
16485                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16486                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16487                                                  tag,
16488                                                  tbinfo->dobj.namespace->dobj.name,
16489                                                  NULL,
16490                                                  tbinfo->rolname,
16491                                                  "FK CONSTRAINT", SECTION_POST_DATA,
16492                                                  q->data, delq->data, NULL,
16493                                                  NULL, 0,
16494                                                  NULL, NULL);
16495         }
16496         else if (coninfo->contype == 'c' && tbinfo)
16497         {
16498                 /* CHECK constraint on a table */
16499
16500                 /* Ignore if not to be dumped separately, or if it was inherited */
16501                 if (coninfo->separate && coninfo->conislocal)
16502                 {
16503                         /* not ONLY since we want it to propagate to children */
16504                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16505                                                           fmtQualifiedDumpable(tbinfo));
16506                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16507                                                           fmtId(coninfo->dobj.name),
16508                                                           coninfo->condef);
16509
16510                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16511                                                           fmtQualifiedDumpable(tbinfo));
16512                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16513                                                           fmtId(coninfo->dobj.name));
16514
16515                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16516
16517                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16518                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16519                                                          tag,
16520                                                          tbinfo->dobj.namespace->dobj.name,
16521                                                          NULL,
16522                                                          tbinfo->rolname,
16523                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16524                                                          q->data, delq->data, NULL,
16525                                                          NULL, 0,
16526                                                          NULL, NULL);
16527                 }
16528         }
16529         else if (coninfo->contype == 'c' && tbinfo == NULL)
16530         {
16531                 /* CHECK constraint on a domain */
16532                 TypeInfo   *tyinfo = coninfo->condomain;
16533
16534                 /* Ignore if not to be dumped separately */
16535                 if (coninfo->separate)
16536                 {
16537                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16538                                                           fmtQualifiedDumpable(tyinfo));
16539                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16540                                                           fmtId(coninfo->dobj.name),
16541                                                           coninfo->condef);
16542
16543                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16544                                                           fmtQualifiedDumpable(tyinfo));
16545                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16546                                                           fmtId(coninfo->dobj.name));
16547
16548                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16549
16550                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16551                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16552                                                          tag,
16553                                                          tyinfo->dobj.namespace->dobj.name,
16554                                                          NULL,
16555                                                          tyinfo->rolname,
16556                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16557                                                          q->data, delq->data, NULL,
16558                                                          NULL, 0,
16559                                                          NULL, NULL);
16560                 }
16561         }
16562         else
16563         {
16564                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16565                                           coninfo->contype);
16566         }
16567
16568         /* Dump Constraint Comments --- only works for table constraints */
16569         if (tbinfo && coninfo->separate &&
16570                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16571                 dumpTableConstraintComment(fout, coninfo);
16572
16573         free(tag);
16574         destroyPQExpBuffer(q);
16575         destroyPQExpBuffer(delq);
16576 }
16577
16578 /*
16579  * dumpTableConstraintComment --- dump a constraint's comment if any
16580  *
16581  * This is split out because we need the function in two different places
16582  * depending on whether the constraint is dumped as part of CREATE TABLE
16583  * or as a separate ALTER command.
16584  */
16585 static void
16586 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16587 {
16588         TableInfo  *tbinfo = coninfo->contable;
16589         PQExpBuffer conprefix = createPQExpBuffer();
16590         char       *qtabname;
16591
16592         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16593
16594         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16595                                           fmtId(coninfo->dobj.name));
16596
16597         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16598                 dumpComment(fout, conprefix->data, qtabname,
16599                                         tbinfo->dobj.namespace->dobj.name,
16600                                         tbinfo->rolname,
16601                                         coninfo->dobj.catId, 0,
16602                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16603
16604         destroyPQExpBuffer(conprefix);
16605         free(qtabname);
16606 }
16607
16608 /*
16609  * findLastBuiltinOid_V71 -
16610  *
16611  * find the last built in oid
16612  *
16613  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16614  * pg_database entry for the current database.  (Note: current_database()
16615  * requires 7.3; pg_dump requires 8.0 now.)
16616  */
16617 static Oid
16618 findLastBuiltinOid_V71(Archive *fout)
16619 {
16620         PGresult   *res;
16621         Oid                     last_oid;
16622
16623         res = ExecuteSqlQueryForSingleRow(fout,
16624                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16625         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16626         PQclear(res);
16627
16628         return last_oid;
16629 }
16630
16631 /*
16632  * dumpSequence
16633  *        write the declaration (not data) of one user-defined sequence
16634  */
16635 static void
16636 dumpSequence(Archive *fout, TableInfo *tbinfo)
16637 {
16638         DumpOptions *dopt = fout->dopt;
16639         PGresult   *res;
16640         char       *startv,
16641                            *incby,
16642                            *maxv,
16643                            *minv,
16644                            *cache,
16645                            *seqtype;
16646         bool            cycled;
16647         bool            is_ascending;
16648         int64           default_minv,
16649                                 default_maxv;
16650         char            bufm[32],
16651                                 bufx[32];
16652         PQExpBuffer query = createPQExpBuffer();
16653         PQExpBuffer delqry = createPQExpBuffer();
16654         char       *qseqname;
16655
16656         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16657
16658         if (fout->remoteVersion >= 100000)
16659         {
16660                 appendPQExpBuffer(query,
16661                                                   "SELECT format_type(seqtypid, NULL), "
16662                                                   "seqstart, seqincrement, "
16663                                                   "seqmax, seqmin, "
16664                                                   "seqcache, seqcycle "
16665                                                   "FROM pg_catalog.pg_sequence "
16666                                                   "WHERE seqrelid = '%u'::oid",
16667                                                   tbinfo->dobj.catId.oid);
16668         }
16669         else if (fout->remoteVersion >= 80400)
16670         {
16671                 /*
16672                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16673                  *
16674                  * Note: it might seem that 'bigint' potentially needs to be
16675                  * schema-qualified, but actually that's a keyword.
16676                  */
16677                 appendPQExpBuffer(query,
16678                                                   "SELECT 'bigint' AS sequence_type, "
16679                                                   "start_value, increment_by, max_value, min_value, "
16680                                                   "cache_value, is_cycled FROM %s",
16681                                                   fmtQualifiedDumpable(tbinfo));
16682         }
16683         else
16684         {
16685                 appendPQExpBuffer(query,
16686                                                   "SELECT 'bigint' AS sequence_type, "
16687                                                   "0 AS start_value, increment_by, max_value, min_value, "
16688                                                   "cache_value, is_cycled FROM %s",
16689                                                   fmtQualifiedDumpable(tbinfo));
16690         }
16691
16692         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16693
16694         if (PQntuples(res) != 1)
16695         {
16696                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16697                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16698                                                                  PQntuples(res)),
16699                                   tbinfo->dobj.name, PQntuples(res));
16700                 exit_nicely(1);
16701         }
16702
16703         seqtype = PQgetvalue(res, 0, 0);
16704         startv = PQgetvalue(res, 0, 1);
16705         incby = PQgetvalue(res, 0, 2);
16706         maxv = PQgetvalue(res, 0, 3);
16707         minv = PQgetvalue(res, 0, 4);
16708         cache = PQgetvalue(res, 0, 5);
16709         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16710
16711         /* Calculate default limits for a sequence of this type */
16712         is_ascending = (incby[0] != '-');
16713         if (strcmp(seqtype, "smallint") == 0)
16714         {
16715                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16716                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16717         }
16718         else if (strcmp(seqtype, "integer") == 0)
16719         {
16720                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16721                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16722         }
16723         else if (strcmp(seqtype, "bigint") == 0)
16724         {
16725                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16726                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16727         }
16728         else
16729         {
16730                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16731                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16732         }
16733
16734         /*
16735          * 64-bit strtol() isn't very portable, so convert the limits to strings
16736          * and compare that way.
16737          */
16738         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16739         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16740
16741         /* Don't print minv/maxv if they match the respective default limit */
16742         if (strcmp(minv, bufm) == 0)
16743                 minv = NULL;
16744         if (strcmp(maxv, bufx) == 0)
16745                 maxv = NULL;
16746
16747         /*
16748          * Identity sequences are not to be dropped separately.
16749          */
16750         if (!tbinfo->is_identity_sequence)
16751         {
16752                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16753                                                   fmtQualifiedDumpable(tbinfo));
16754         }
16755
16756         resetPQExpBuffer(query);
16757
16758         if (dopt->binary_upgrade)
16759         {
16760                 binary_upgrade_set_pg_class_oids(fout, query,
16761                                                                                  tbinfo->dobj.catId.oid, false);
16762                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16763                                                                                                 tbinfo->dobj.catId.oid);
16764         }
16765
16766         if (tbinfo->is_identity_sequence)
16767         {
16768                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16769
16770                 appendPQExpBuffer(query,
16771                                                   "ALTER TABLE %s ",
16772                                                   fmtQualifiedDumpable(owning_tab));
16773                 appendPQExpBuffer(query,
16774                                                   "ALTER COLUMN %s ADD GENERATED ",
16775                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16776                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16777                         appendPQExpBuffer(query, "ALWAYS");
16778                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16779                         appendPQExpBuffer(query, "BY DEFAULT");
16780                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16781                                                   fmtQualifiedDumpable(tbinfo));
16782         }
16783         else
16784         {
16785                 appendPQExpBuffer(query,
16786                                                   "CREATE SEQUENCE %s\n",
16787                                                   fmtQualifiedDumpable(tbinfo));
16788
16789                 if (strcmp(seqtype, "bigint") != 0)
16790                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16791         }
16792
16793         if (fout->remoteVersion >= 80400)
16794                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16795
16796         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16797
16798         if (minv)
16799                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16800         else
16801                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16802
16803         if (maxv)
16804                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16805         else
16806                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16807
16808         appendPQExpBuffer(query,
16809                                           "    CACHE %s%s",
16810                                           cache, (cycled ? "\n    CYCLE" : ""));
16811
16812         if (tbinfo->is_identity_sequence)
16813                 appendPQExpBufferStr(query, "\n);\n");
16814         else
16815                 appendPQExpBufferStr(query, ";\n");
16816
16817         /* binary_upgrade:      no need to clear TOAST table oid */
16818
16819         if (dopt->binary_upgrade)
16820                 binary_upgrade_extension_member(query, &tbinfo->dobj,
16821                                                                                 "SEQUENCE", qseqname,
16822                                                                                 tbinfo->dobj.namespace->dobj.name);
16823
16824         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16825                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16826                                          tbinfo->dobj.name,
16827                                          tbinfo->dobj.namespace->dobj.name,
16828                                          NULL,
16829                                          tbinfo->rolname,
16830                                          "SEQUENCE", SECTION_PRE_DATA,
16831                                          query->data, delqry->data, NULL,
16832                                          NULL, 0,
16833                                          NULL, NULL);
16834
16835         /*
16836          * If the sequence is owned by a table column, emit the ALTER for it as a
16837          * separate TOC entry immediately following the sequence's own entry. It's
16838          * OK to do this rather than using full sorting logic, because the
16839          * dependency that tells us it's owned will have forced the table to be
16840          * created first.  We can't just include the ALTER in the TOC entry
16841          * because it will fail if we haven't reassigned the sequence owner to
16842          * match the table's owner.
16843          *
16844          * We need not schema-qualify the table reference because both sequence
16845          * and table must be in the same schema.
16846          */
16847         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
16848         {
16849                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16850
16851                 if (owning_tab == NULL)
16852                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
16853                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16854
16855                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16856                 {
16857                         resetPQExpBuffer(query);
16858                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16859                                                           fmtQualifiedDumpable(tbinfo));
16860                         appendPQExpBuffer(query, " OWNED BY %s",
16861                                                           fmtQualifiedDumpable(owning_tab));
16862                         appendPQExpBuffer(query, ".%s;\n",
16863                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16864
16865                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16866                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16867                                                          tbinfo->dobj.name,
16868                                                          tbinfo->dobj.namespace->dobj.name,
16869                                                          NULL,
16870                                                          tbinfo->rolname,
16871                                                          "SEQUENCE OWNED BY", SECTION_PRE_DATA,
16872                                                          query->data, "", NULL,
16873                                                          &(tbinfo->dobj.dumpId), 1,
16874                                                          NULL, NULL);
16875                 }
16876         }
16877
16878         /* Dump Sequence Comments and Security Labels */
16879         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16880                 dumpComment(fout, "SEQUENCE", qseqname,
16881                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16882                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16883
16884         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16885                 dumpSecLabel(fout, "SEQUENCE", qseqname,
16886                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16887                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16888
16889         PQclear(res);
16890
16891         destroyPQExpBuffer(query);
16892         destroyPQExpBuffer(delqry);
16893         free(qseqname);
16894 }
16895
16896 /*
16897  * dumpSequenceData
16898  *        write the data of one user-defined sequence
16899  */
16900 static void
16901 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16902 {
16903         TableInfo  *tbinfo = tdinfo->tdtable;
16904         PGresult   *res;
16905         char       *last;
16906         bool            called;
16907         PQExpBuffer query = createPQExpBuffer();
16908
16909         appendPQExpBuffer(query,
16910                                           "SELECT last_value, is_called FROM %s",
16911                                           fmtQualifiedDumpable(tbinfo));
16912
16913         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16914
16915         if (PQntuples(res) != 1)
16916         {
16917                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16918                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16919                                                                  PQntuples(res)),
16920                                   tbinfo->dobj.name, PQntuples(res));
16921                 exit_nicely(1);
16922         }
16923
16924         last = PQgetvalue(res, 0, 0);
16925         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
16926
16927         resetPQExpBuffer(query);
16928         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
16929         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
16930         appendPQExpBuffer(query, ", %s, %s);\n",
16931                                           last, (called ? "true" : "false"));
16932
16933         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
16934                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16935                                          tbinfo->dobj.name,
16936                                          tbinfo->dobj.namespace->dobj.name,
16937                                          NULL,
16938                                          tbinfo->rolname,
16939                                          "SEQUENCE SET", SECTION_DATA,
16940                                          query->data, "", NULL,
16941                                          &(tbinfo->dobj.dumpId), 1,
16942                                          NULL, NULL);
16943
16944         PQclear(res);
16945
16946         destroyPQExpBuffer(query);
16947 }
16948
16949 /*
16950  * dumpTrigger
16951  *        write the declaration of one user-defined table trigger
16952  */
16953 static void
16954 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
16955 {
16956         DumpOptions *dopt = fout->dopt;
16957         TableInfo  *tbinfo = tginfo->tgtable;
16958         PQExpBuffer query;
16959         PQExpBuffer delqry;
16960         PQExpBuffer trigprefix;
16961         char       *qtabname;
16962         char       *tgargs;
16963         size_t          lentgargs;
16964         const char *p;
16965         int                     findx;
16966         char       *tag;
16967
16968         /*
16969          * we needn't check dobj.dump because TriggerInfo wouldn't have been
16970          * created in the first place for non-dumpable triggers
16971          */
16972         if (dopt->dataOnly)
16973                 return;
16974
16975         query = createPQExpBuffer();
16976         delqry = createPQExpBuffer();
16977         trigprefix = createPQExpBuffer();
16978
16979         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16980
16981         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
16982                                           fmtId(tginfo->dobj.name));
16983         appendPQExpBuffer(delqry, "ON %s;\n",
16984                                           fmtQualifiedDumpable(tbinfo));
16985
16986         if (tginfo->tgdef)
16987         {
16988                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
16989         }
16990         else
16991         {
16992                 if (tginfo->tgisconstraint)
16993                 {
16994                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
16995                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
16996                 }
16997                 else
16998                 {
16999                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17000                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17001                 }
17002                 appendPQExpBufferStr(query, "\n    ");
17003
17004                 /* Trigger type */
17005                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17006                         appendPQExpBufferStr(query, "BEFORE");
17007                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17008                         appendPQExpBufferStr(query, "AFTER");
17009                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17010                         appendPQExpBufferStr(query, "INSTEAD OF");
17011                 else
17012                 {
17013                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17014                         exit_nicely(1);
17015                 }
17016
17017                 findx = 0;
17018                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17019                 {
17020                         appendPQExpBufferStr(query, " INSERT");
17021                         findx++;
17022                 }
17023                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17024                 {
17025                         if (findx > 0)
17026                                 appendPQExpBufferStr(query, " OR DELETE");
17027                         else
17028                                 appendPQExpBufferStr(query, " DELETE");
17029                         findx++;
17030                 }
17031                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17032                 {
17033                         if (findx > 0)
17034                                 appendPQExpBufferStr(query, " OR UPDATE");
17035                         else
17036                                 appendPQExpBufferStr(query, " UPDATE");
17037                         findx++;
17038                 }
17039                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17040                 {
17041                         if (findx > 0)
17042                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17043                         else
17044                                 appendPQExpBufferStr(query, " TRUNCATE");
17045                         findx++;
17046                 }
17047                 appendPQExpBuffer(query, " ON %s\n",
17048                                                   fmtQualifiedDumpable(tbinfo));
17049
17050                 if (tginfo->tgisconstraint)
17051                 {
17052                         if (OidIsValid(tginfo->tgconstrrelid))
17053                         {
17054                                 /* regclass output is already quoted */
17055                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17056                                                                   tginfo->tgconstrrelname);
17057                         }
17058                         if (!tginfo->tgdeferrable)
17059                                 appendPQExpBufferStr(query, "NOT ");
17060                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17061                         if (tginfo->tginitdeferred)
17062                                 appendPQExpBufferStr(query, "DEFERRED\n");
17063                         else
17064                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17065                 }
17066
17067                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17068                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17069                 else
17070                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17071
17072                 /* regproc output is already sufficiently quoted */
17073                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
17074                                                   tginfo->tgfname);
17075
17076                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17077                                                                                   &lentgargs);
17078                 p = tgargs;
17079                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17080                 {
17081                         /* find the embedded null that terminates this trigger argument */
17082                         size_t          tlen = strlen(p);
17083
17084                         if (p + tlen >= tgargs + lentgargs)
17085                         {
17086                                 /* hm, not found before end of bytea value... */
17087                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17088                                                   tginfo->tgargs,
17089                                                   tginfo->dobj.name,
17090                                                   tbinfo->dobj.name);
17091                                 exit_nicely(1);
17092                         }
17093
17094                         if (findx > 0)
17095                                 appendPQExpBufferStr(query, ", ");
17096                         appendStringLiteralAH(query, p, fout);
17097                         p += tlen + 1;
17098                 }
17099                 free(tgargs);
17100                 appendPQExpBufferStr(query, ");\n");
17101         }
17102
17103         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17104         {
17105                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17106                                                   fmtQualifiedDumpable(tbinfo));
17107                 switch (tginfo->tgenabled)
17108                 {
17109                         case 'D':
17110                         case 'f':
17111                                 appendPQExpBufferStr(query, "DISABLE");
17112                                 break;
17113                         case 'A':
17114                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17115                                 break;
17116                         case 'R':
17117                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17118                                 break;
17119                         default:
17120                                 appendPQExpBufferStr(query, "ENABLE");
17121                                 break;
17122                 }
17123                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17124                                                   fmtId(tginfo->dobj.name));
17125         }
17126
17127         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17128                                           fmtId(tginfo->dobj.name));
17129
17130         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17131
17132         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17133                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17134                                          tag,
17135                                          tbinfo->dobj.namespace->dobj.name,
17136                                          NULL,
17137                                          tbinfo->rolname,
17138                                          "TRIGGER", SECTION_POST_DATA,
17139                                          query->data, delqry->data, NULL,
17140                                          NULL, 0,
17141                                          NULL, NULL);
17142
17143         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17144                 dumpComment(fout, trigprefix->data, qtabname,
17145                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17146                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17147
17148         free(tag);
17149         destroyPQExpBuffer(query);
17150         destroyPQExpBuffer(delqry);
17151         destroyPQExpBuffer(trigprefix);
17152         free(qtabname);
17153 }
17154
17155 /*
17156  * dumpEventTrigger
17157  *        write the declaration of one user-defined event trigger
17158  */
17159 static void
17160 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17161 {
17162         DumpOptions *dopt = fout->dopt;
17163         PQExpBuffer query;
17164         PQExpBuffer delqry;
17165         char       *qevtname;
17166
17167         /* Skip if not to be dumped */
17168         if (!evtinfo->dobj.dump || dopt->dataOnly)
17169                 return;
17170
17171         query = createPQExpBuffer();
17172         delqry = createPQExpBuffer();
17173
17174         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17175
17176         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17177         appendPQExpBufferStr(query, qevtname);
17178         appendPQExpBufferStr(query, " ON ");
17179         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17180
17181         if (strcmp("", evtinfo->evttags) != 0)
17182         {
17183                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17184                 appendPQExpBufferStr(query, evtinfo->evttags);
17185                 appendPQExpBufferChar(query, ')');
17186         }
17187
17188         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
17189         appendPQExpBufferStr(query, evtinfo->evtfname);
17190         appendPQExpBufferStr(query, "();\n");
17191
17192         if (evtinfo->evtenabled != 'O')
17193         {
17194                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17195                                                   qevtname);
17196                 switch (evtinfo->evtenabled)
17197                 {
17198                         case 'D':
17199                                 appendPQExpBufferStr(query, "DISABLE");
17200                                 break;
17201                         case 'A':
17202                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17203                                 break;
17204                         case 'R':
17205                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17206                                 break;
17207                         default:
17208                                 appendPQExpBufferStr(query, "ENABLE");
17209                                 break;
17210                 }
17211                 appendPQExpBufferStr(query, ";\n");
17212         }
17213
17214         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17215                                           qevtname);
17216
17217         if (dopt->binary_upgrade)
17218                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17219                                                                                 "EVENT TRIGGER", qevtname, NULL);
17220
17221         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17222                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17223                                          evtinfo->dobj.name, NULL, NULL,
17224                                          evtinfo->evtowner,
17225                                          "EVENT TRIGGER", SECTION_POST_DATA,
17226                                          query->data, delqry->data, NULL,
17227                                          NULL, 0,
17228                                          NULL, NULL);
17229
17230         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17231                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17232                                         NULL, evtinfo->evtowner,
17233                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17234
17235         destroyPQExpBuffer(query);
17236         destroyPQExpBuffer(delqry);
17237         free(qevtname);
17238 }
17239
17240 /*
17241  * dumpRule
17242  *              Dump a rule
17243  */
17244 static void
17245 dumpRule(Archive *fout, RuleInfo *rinfo)
17246 {
17247         DumpOptions *dopt = fout->dopt;
17248         TableInfo  *tbinfo = rinfo->ruletable;
17249         bool            is_view;
17250         PQExpBuffer query;
17251         PQExpBuffer cmd;
17252         PQExpBuffer delcmd;
17253         PQExpBuffer ruleprefix;
17254         char       *qtabname;
17255         PGresult   *res;
17256         char       *tag;
17257
17258         /* Skip if not to be dumped */
17259         if (!rinfo->dobj.dump || dopt->dataOnly)
17260                 return;
17261
17262         /*
17263          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17264          * we do not want to dump it as a separate object.
17265          */
17266         if (!rinfo->separate)
17267                 return;
17268
17269         /*
17270          * If it's an ON SELECT rule, we want to print it as a view definition,
17271          * instead of a rule.
17272          */
17273         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17274
17275         query = createPQExpBuffer();
17276         cmd = createPQExpBuffer();
17277         delcmd = createPQExpBuffer();
17278         ruleprefix = createPQExpBuffer();
17279
17280         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17281
17282         if (is_view)
17283         {
17284                 PQExpBuffer result;
17285
17286                 /*
17287                  * We need OR REPLACE here because we'll be replacing a dummy view.
17288                  * Otherwise this should look largely like the regular view dump code.
17289                  */
17290                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17291                                                   fmtQualifiedDumpable(tbinfo));
17292                 if (nonemptyReloptions(tbinfo->reloptions))
17293                 {
17294                         appendPQExpBufferStr(cmd, " WITH (");
17295                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17296                         appendPQExpBufferChar(cmd, ')');
17297                 }
17298                 result = createViewAsClause(fout, tbinfo);
17299                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17300                 destroyPQExpBuffer(result);
17301                 if (tbinfo->checkoption != NULL)
17302                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17303                                                           tbinfo->checkoption);
17304                 appendPQExpBufferStr(cmd, ";\n");
17305         }
17306         else
17307         {
17308                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17309                 appendPQExpBuffer(query,
17310                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17311                                                   rinfo->dobj.catId.oid);
17312
17313                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17314
17315                 if (PQntuples(res) != 1)
17316                 {
17317                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17318                                           rinfo->dobj.name, tbinfo->dobj.name);
17319                         exit_nicely(1);
17320                 }
17321
17322                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17323
17324                 PQclear(res);
17325         }
17326
17327         /*
17328          * Add the command to alter the rules replication firing semantics if it
17329          * differs from the default.
17330          */
17331         if (rinfo->ev_enabled != 'O')
17332         {
17333                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17334                 switch (rinfo->ev_enabled)
17335                 {
17336                         case 'A':
17337                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17338                                                                   fmtId(rinfo->dobj.name));
17339                                 break;
17340                         case 'R':
17341                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17342                                                                   fmtId(rinfo->dobj.name));
17343                                 break;
17344                         case 'D':
17345                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17346                                                                   fmtId(rinfo->dobj.name));
17347                                 break;
17348                 }
17349         }
17350
17351         if (is_view)
17352         {
17353                 /*
17354                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17355                  * REPLACE VIEW to replace the rule with something with minimal
17356                  * dependencies.
17357                  */
17358                 PQExpBuffer result;
17359
17360                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17361                                                   fmtQualifiedDumpable(tbinfo));
17362                 result = createDummyViewAsClause(fout, tbinfo);
17363                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17364                 destroyPQExpBuffer(result);
17365         }
17366         else
17367         {
17368                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17369                                                   fmtId(rinfo->dobj.name));
17370                 appendPQExpBuffer(delcmd, "ON %s;\n",
17371                                                   fmtQualifiedDumpable(tbinfo));
17372         }
17373
17374         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17375                                           fmtId(rinfo->dobj.name));
17376
17377         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17378
17379         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17380                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17381                                          tag,
17382                                          tbinfo->dobj.namespace->dobj.name,
17383                                          NULL,
17384                                          tbinfo->rolname,
17385                                          "RULE", SECTION_POST_DATA,
17386                                          cmd->data, delcmd->data, NULL,
17387                                          NULL, 0,
17388                                          NULL, NULL);
17389
17390         /* Dump rule comments */
17391         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17392                 dumpComment(fout, ruleprefix->data, qtabname,
17393                                         tbinfo->dobj.namespace->dobj.name,
17394                                         tbinfo->rolname,
17395                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17396
17397         free(tag);
17398         destroyPQExpBuffer(query);
17399         destroyPQExpBuffer(cmd);
17400         destroyPQExpBuffer(delcmd);
17401         destroyPQExpBuffer(ruleprefix);
17402         free(qtabname);
17403 }
17404
17405 /*
17406  * getExtensionMembership --- obtain extension membership data
17407  *
17408  * We need to identify objects that are extension members as soon as they're
17409  * loaded, so that we can correctly determine whether they need to be dumped.
17410  * Generally speaking, extension member objects will get marked as *not* to
17411  * be dumped, as they will be recreated by the single CREATE EXTENSION
17412  * command.  However, in binary upgrade mode we still need to dump the members
17413  * individually.
17414  */
17415 void
17416 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17417                                            int numExtensions)
17418 {
17419         PQExpBuffer query;
17420         PGresult   *res;
17421         int                     ntups,
17422                                 nextmembers,
17423                                 i;
17424         int                     i_classid,
17425                                 i_objid,
17426                                 i_refobjid;
17427         ExtensionMemberId *extmembers;
17428         ExtensionInfo *ext;
17429
17430         /* Nothing to do if no extensions */
17431         if (numExtensions == 0)
17432                 return;
17433
17434         query = createPQExpBuffer();
17435
17436         /* refclassid constraint is redundant but may speed the search */
17437         appendPQExpBufferStr(query, "SELECT "
17438                                                  "classid, objid, refobjid "
17439                                                  "FROM pg_depend "
17440                                                  "WHERE refclassid = 'pg_extension'::regclass "
17441                                                  "AND deptype = 'e' "
17442                                                  "ORDER BY 3");
17443
17444         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17445
17446         ntups = PQntuples(res);
17447
17448         i_classid = PQfnumber(res, "classid");
17449         i_objid = PQfnumber(res, "objid");
17450         i_refobjid = PQfnumber(res, "refobjid");
17451
17452         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17453         nextmembers = 0;
17454
17455         /*
17456          * Accumulate data into extmembers[].
17457          *
17458          * Since we ordered the SELECT by referenced ID, we can expect that
17459          * multiple entries for the same extension will appear together; this
17460          * saves on searches.
17461          */
17462         ext = NULL;
17463
17464         for (i = 0; i < ntups; i++)
17465         {
17466                 CatalogId       objId;
17467                 Oid                     extId;
17468
17469                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17470                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17471                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17472
17473                 if (ext == NULL ||
17474                         ext->dobj.catId.oid != extId)
17475                         ext = findExtensionByOid(extId);
17476
17477                 if (ext == NULL)
17478                 {
17479                         /* shouldn't happen */
17480                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17481                         continue;
17482                 }
17483
17484                 extmembers[nextmembers].catId = objId;
17485                 extmembers[nextmembers].ext = ext;
17486                 nextmembers++;
17487         }
17488
17489         PQclear(res);
17490
17491         /* Remember the data for use later */
17492         setExtensionMembership(extmembers, nextmembers);
17493
17494         destroyPQExpBuffer(query);
17495 }
17496
17497 /*
17498  * processExtensionTables --- deal with extension configuration tables
17499  *
17500  * There are two parts to this process:
17501  *
17502  * 1. Identify and create dump records for extension configuration tables.
17503  *
17504  *        Extensions can mark tables as "configuration", which means that the user
17505  *        is able and expected to modify those tables after the extension has been
17506  *        loaded.  For these tables, we dump out only the data- the structure is
17507  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17508  *        foreign keys, which brings us to-
17509  *
17510  * 2. Record FK dependencies between configuration tables.
17511  *
17512  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17513  *        the data is loaded, we have to work out what the best order for reloading
17514  *        the data is, to avoid FK violations when the tables are restored.  This is
17515  *        not perfect- we can't handle circular dependencies and if any exist they
17516  *        will cause an invalid dump to be produced (though at least all of the data
17517  *        is included for a user to manually restore).  This is currently documented
17518  *        but perhaps we can provide a better solution in the future.
17519  */
17520 void
17521 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17522                                            int numExtensions)
17523 {
17524         DumpOptions *dopt = fout->dopt;
17525         PQExpBuffer query;
17526         PGresult   *res;
17527         int                     ntups,
17528                                 i;
17529         int                     i_conrelid,
17530                                 i_confrelid;
17531
17532         /* Nothing to do if no extensions */
17533         if (numExtensions == 0)
17534                 return;
17535
17536         /*
17537          * Identify extension configuration tables and create TableDataInfo
17538          * objects for them, ensuring their data will be dumped even though the
17539          * tables themselves won't be.
17540          *
17541          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17542          * user data in a configuration table is treated like schema data. This
17543          * seems appropriate since system data in a config table would get
17544          * reloaded by CREATE EXTENSION.
17545          */
17546         for (i = 0; i < numExtensions; i++)
17547         {
17548                 ExtensionInfo *curext = &(extinfo[i]);
17549                 char       *extconfig = curext->extconfig;
17550                 char       *extcondition = curext->extcondition;
17551                 char      **extconfigarray = NULL;
17552                 char      **extconditionarray = NULL;
17553                 int                     nconfigitems;
17554                 int                     nconditionitems;
17555
17556                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17557                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17558                         nconfigitems == nconditionitems)
17559                 {
17560                         int                     j;
17561
17562                         for (j = 0; j < nconfigitems; j++)
17563                         {
17564                                 TableInfo  *configtbl;
17565                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17566                                 bool            dumpobj =
17567                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17568
17569                                 configtbl = findTableByOid(configtbloid);
17570                                 if (configtbl == NULL)
17571                                         continue;
17572
17573                                 /*
17574                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17575                                  * unless the table or its schema is explicitly included
17576                                  */
17577                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17578                                 {
17579                                         /* check table explicitly requested */
17580                                         if (table_include_oids.head != NULL &&
17581                                                 simple_oid_list_member(&table_include_oids,
17582                                                                                            configtbloid))
17583                                                 dumpobj = true;
17584
17585                                         /* check table's schema explicitly requested */
17586                                         if (configtbl->dobj.namespace->dobj.dump &
17587                                                 DUMP_COMPONENT_DATA)
17588                                                 dumpobj = true;
17589                                 }
17590
17591                                 /* check table excluded by an exclusion switch */
17592                                 if (table_exclude_oids.head != NULL &&
17593                                         simple_oid_list_member(&table_exclude_oids,
17594                                                                                    configtbloid))
17595                                         dumpobj = false;
17596
17597                                 /* check schema excluded by an exclusion switch */
17598                                 if (simple_oid_list_member(&schema_exclude_oids,
17599                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17600                                         dumpobj = false;
17601
17602                                 if (dumpobj)
17603                                 {
17604                                         makeTableDataInfo(dopt, configtbl);
17605                                         if (configtbl->dataObj != NULL)
17606                                         {
17607                                                 if (strlen(extconditionarray[j]) > 0)
17608                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17609                                         }
17610                                 }
17611                         }
17612                 }
17613                 if (extconfigarray)
17614                         free(extconfigarray);
17615                 if (extconditionarray)
17616                         free(extconditionarray);
17617         }
17618
17619         /*
17620          * Now that all the TableInfoData objects have been created for all the
17621          * extensions, check their FK dependencies and register them to try and
17622          * dump the data out in an order that they can be restored in.
17623          *
17624          * Note that this is not a problem for user tables as their FKs are
17625          * recreated after the data has been loaded.
17626          */
17627
17628         query = createPQExpBuffer();
17629
17630         printfPQExpBuffer(query,
17631                                           "SELECT conrelid, confrelid "
17632                                           "FROM pg_constraint "
17633                                           "JOIN pg_depend ON (objid = confrelid) "
17634                                           "WHERE contype = 'f' "
17635                                           "AND refclassid = 'pg_extension'::regclass "
17636                                           "AND classid = 'pg_class'::regclass;");
17637
17638         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17639         ntups = PQntuples(res);
17640
17641         i_conrelid = PQfnumber(res, "conrelid");
17642         i_confrelid = PQfnumber(res, "confrelid");
17643
17644         /* Now get the dependencies and register them */
17645         for (i = 0; i < ntups; i++)
17646         {
17647                 Oid                     conrelid,
17648                                         confrelid;
17649                 TableInfo  *reftable,
17650                                    *contable;
17651
17652                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17653                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17654                 contable = findTableByOid(conrelid);
17655                 reftable = findTableByOid(confrelid);
17656
17657                 if (reftable == NULL ||
17658                         reftable->dataObj == NULL ||
17659                         contable == NULL ||
17660                         contable->dataObj == NULL)
17661                         continue;
17662
17663                 /*
17664                  * Make referencing TABLE_DATA object depend on the referenced table's
17665                  * TABLE_DATA object.
17666                  */
17667                 addObjectDependency(&contable->dataObj->dobj,
17668                                                         reftable->dataObj->dobj.dumpId);
17669         }
17670         PQclear(res);
17671         destroyPQExpBuffer(query);
17672 }
17673
17674 /*
17675  * getDependencies --- obtain available dependency data
17676  */
17677 static void
17678 getDependencies(Archive *fout)
17679 {
17680         PQExpBuffer query;
17681         PGresult   *res;
17682         int                     ntups,
17683                                 i;
17684         int                     i_classid,
17685                                 i_objid,
17686                                 i_refclassid,
17687                                 i_refobjid,
17688                                 i_deptype;
17689         DumpableObject *dobj,
17690                            *refdobj;
17691
17692         if (g_verbose)
17693                 write_msg(NULL, "reading dependency data\n");
17694
17695         query = createPQExpBuffer();
17696
17697         /*
17698          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17699          * already processed by getExtensionMembership.
17700          */
17701         appendPQExpBufferStr(query, "SELECT "
17702                                                  "classid, objid, refclassid, refobjid, deptype "
17703                                                  "FROM pg_depend "
17704                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17705                                                  "ORDER BY 1,2");
17706
17707         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17708
17709         ntups = PQntuples(res);
17710
17711         i_classid = PQfnumber(res, "classid");
17712         i_objid = PQfnumber(res, "objid");
17713         i_refclassid = PQfnumber(res, "refclassid");
17714         i_refobjid = PQfnumber(res, "refobjid");
17715         i_deptype = PQfnumber(res, "deptype");
17716
17717         /*
17718          * Since we ordered the SELECT by referencing ID, we can expect that
17719          * multiple entries for the same object will appear together; this saves
17720          * on searches.
17721          */
17722         dobj = NULL;
17723
17724         for (i = 0; i < ntups; i++)
17725         {
17726                 CatalogId       objId;
17727                 CatalogId       refobjId;
17728                 char            deptype;
17729
17730                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17731                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17732                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17733                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17734                 deptype = *(PQgetvalue(res, i, i_deptype));
17735
17736                 if (dobj == NULL ||
17737                         dobj->catId.tableoid != objId.tableoid ||
17738                         dobj->catId.oid != objId.oid)
17739                         dobj = findObjectByCatalogId(objId);
17740
17741                 /*
17742                  * Failure to find objects mentioned in pg_depend is not unexpected,
17743                  * since for example we don't collect info about TOAST tables.
17744                  */
17745                 if (dobj == NULL)
17746                 {
17747 #ifdef NOT_USED
17748                         fprintf(stderr, "no referencing object %u %u\n",
17749                                         objId.tableoid, objId.oid);
17750 #endif
17751                         continue;
17752                 }
17753
17754                 refdobj = findObjectByCatalogId(refobjId);
17755
17756                 if (refdobj == NULL)
17757                 {
17758 #ifdef NOT_USED
17759                         fprintf(stderr, "no referenced object %u %u\n",
17760                                         refobjId.tableoid, refobjId.oid);
17761 #endif
17762                         continue;
17763                 }
17764
17765                 /*
17766                  * Ordinarily, table rowtypes have implicit dependencies on their
17767                  * tables.  However, for a composite type the implicit dependency goes
17768                  * the other way in pg_depend; which is the right thing for DROP but
17769                  * it doesn't produce the dependency ordering we need. So in that one
17770                  * case, we reverse the direction of the dependency.
17771                  */
17772                 if (deptype == 'i' &&
17773                         dobj->objType == DO_TABLE &&
17774                         refdobj->objType == DO_TYPE)
17775                         addObjectDependency(refdobj, dobj->dumpId);
17776                 else
17777                         /* normal case */
17778                         addObjectDependency(dobj, refdobj->dumpId);
17779         }
17780
17781         PQclear(res);
17782
17783         destroyPQExpBuffer(query);
17784 }
17785
17786
17787 /*
17788  * createBoundaryObjects - create dummy DumpableObjects to represent
17789  * dump section boundaries.
17790  */
17791 static DumpableObject *
17792 createBoundaryObjects(void)
17793 {
17794         DumpableObject *dobjs;
17795
17796         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17797
17798         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17799         dobjs[0].catId = nilCatalogId;
17800         AssignDumpId(dobjs + 0);
17801         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17802
17803         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17804         dobjs[1].catId = nilCatalogId;
17805         AssignDumpId(dobjs + 1);
17806         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17807
17808         return dobjs;
17809 }
17810
17811 /*
17812  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17813  * section boundaries.
17814  */
17815 static void
17816 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17817                                                 DumpableObject *boundaryObjs)
17818 {
17819         DumpableObject *preDataBound = boundaryObjs + 0;
17820         DumpableObject *postDataBound = boundaryObjs + 1;
17821         int                     i;
17822
17823         for (i = 0; i < numObjs; i++)
17824         {
17825                 DumpableObject *dobj = dobjs[i];
17826
17827                 /*
17828                  * The classification of object types here must match the SECTION_xxx
17829                  * values assigned during subsequent ArchiveEntry calls!
17830                  */
17831                 switch (dobj->objType)
17832                 {
17833                         case DO_NAMESPACE:
17834                         case DO_EXTENSION:
17835                         case DO_TYPE:
17836                         case DO_SHELL_TYPE:
17837                         case DO_FUNC:
17838                         case DO_AGG:
17839                         case DO_OPERATOR:
17840                         case DO_ACCESS_METHOD:
17841                         case DO_OPCLASS:
17842                         case DO_OPFAMILY:
17843                         case DO_COLLATION:
17844                         case DO_CONVERSION:
17845                         case DO_TABLE:
17846                         case DO_ATTRDEF:
17847                         case DO_PROCLANG:
17848                         case DO_CAST:
17849                         case DO_DUMMY_TYPE:
17850                         case DO_TSPARSER:
17851                         case DO_TSDICT:
17852                         case DO_TSTEMPLATE:
17853                         case DO_TSCONFIG:
17854                         case DO_FDW:
17855                         case DO_FOREIGN_SERVER:
17856                         case DO_TRANSFORM:
17857                         case DO_BLOB:
17858                                 /* Pre-data objects: must come before the pre-data boundary */
17859                                 addObjectDependency(preDataBound, dobj->dumpId);
17860                                 break;
17861                         case DO_TABLE_DATA:
17862                         case DO_SEQUENCE_SET:
17863                         case DO_BLOB_DATA:
17864                                 /* Data objects: must come between the boundaries */
17865                                 addObjectDependency(dobj, preDataBound->dumpId);
17866                                 addObjectDependency(postDataBound, dobj->dumpId);
17867                                 break;
17868                         case DO_INDEX:
17869                         case DO_INDEX_ATTACH:
17870                         case DO_STATSEXT:
17871                         case DO_REFRESH_MATVIEW:
17872                         case DO_TRIGGER:
17873                         case DO_EVENT_TRIGGER:
17874                         case DO_DEFAULT_ACL:
17875                         case DO_POLICY:
17876                         case DO_PUBLICATION:
17877                         case DO_PUBLICATION_REL:
17878                         case DO_SUBSCRIPTION:
17879                                 /* Post-data objects: must come after the post-data boundary */
17880                                 addObjectDependency(dobj, postDataBound->dumpId);
17881                                 break;
17882                         case DO_RULE:
17883                                 /* Rules are post-data, but only if dumped separately */
17884                                 if (((RuleInfo *) dobj)->separate)
17885                                         addObjectDependency(dobj, postDataBound->dumpId);
17886                                 break;
17887                         case DO_CONSTRAINT:
17888                         case DO_FK_CONSTRAINT:
17889                                 /* Constraints are post-data, but only if dumped separately */
17890                                 if (((ConstraintInfo *) dobj)->separate)
17891                                         addObjectDependency(dobj, postDataBound->dumpId);
17892                                 break;
17893                         case DO_PRE_DATA_BOUNDARY:
17894                                 /* nothing to do */
17895                                 break;
17896                         case DO_POST_DATA_BOUNDARY:
17897                                 /* must come after the pre-data boundary */
17898                                 addObjectDependency(dobj, preDataBound->dumpId);
17899                                 break;
17900                 }
17901         }
17902 }
17903
17904
17905 /*
17906  * BuildArchiveDependencies - create dependency data for archive TOC entries
17907  *
17908  * The raw dependency data obtained by getDependencies() is not terribly
17909  * useful in an archive dump, because in many cases there are dependency
17910  * chains linking through objects that don't appear explicitly in the dump.
17911  * For example, a view will depend on its _RETURN rule while the _RETURN rule
17912  * will depend on other objects --- but the rule will not appear as a separate
17913  * object in the dump.  We need to adjust the view's dependencies to include
17914  * whatever the rule depends on that is included in the dump.
17915  *
17916  * Just to make things more complicated, there are also "special" dependencies
17917  * such as the dependency of a TABLE DATA item on its TABLE, which we must
17918  * not rearrange because pg_restore knows that TABLE DATA only depends on
17919  * its table.  In these cases we must leave the dependencies strictly as-is
17920  * even if they refer to not-to-be-dumped objects.
17921  *
17922  * To handle this, the convention is that "special" dependencies are created
17923  * during ArchiveEntry calls, and an archive TOC item that has any such
17924  * entries will not be touched here.  Otherwise, we recursively search the
17925  * DumpableObject data structures to build the correct dependencies for each
17926  * archive TOC item.
17927  */
17928 static void
17929 BuildArchiveDependencies(Archive *fout)
17930 {
17931         ArchiveHandle *AH = (ArchiveHandle *) fout;
17932         TocEntry   *te;
17933
17934         /* Scan all TOC entries in the archive */
17935         for (te = AH->toc->next; te != AH->toc; te = te->next)
17936         {
17937                 DumpableObject *dobj;
17938                 DumpId     *dependencies;
17939                 int                     nDeps;
17940                 int                     allocDeps;
17941
17942                 /* No need to process entries that will not be dumped */
17943                 if (te->reqs == 0)
17944                         continue;
17945                 /* Ignore entries that already have "special" dependencies */
17946                 if (te->nDeps > 0)
17947                         continue;
17948                 /* Otherwise, look up the item's original DumpableObject, if any */
17949                 dobj = findObjectByDumpId(te->dumpId);
17950                 if (dobj == NULL)
17951                         continue;
17952                 /* No work if it has no dependencies */
17953                 if (dobj->nDeps <= 0)
17954                         continue;
17955                 /* Set up work array */
17956                 allocDeps = 64;
17957                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
17958                 nDeps = 0;
17959                 /* Recursively find all dumpable dependencies */
17960                 findDumpableDependencies(AH, dobj,
17961                                                                  &dependencies, &nDeps, &allocDeps);
17962                 /* And save 'em ... */
17963                 if (nDeps > 0)
17964                 {
17965                         dependencies = (DumpId *) pg_realloc(dependencies,
17966                                                                                                  nDeps * sizeof(DumpId));
17967                         te->dependencies = dependencies;
17968                         te->nDeps = nDeps;
17969                 }
17970                 else
17971                         free(dependencies);
17972         }
17973 }
17974
17975 /* Recursive search subroutine for BuildArchiveDependencies */
17976 static void
17977 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
17978                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
17979 {
17980         int                     i;
17981
17982         /*
17983          * Ignore section boundary objects: if we search through them, we'll
17984          * report lots of bogus dependencies.
17985          */
17986         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
17987                 dobj->objType == DO_POST_DATA_BOUNDARY)
17988                 return;
17989
17990         for (i = 0; i < dobj->nDeps; i++)
17991         {
17992                 DumpId          depid = dobj->dependencies[i];
17993
17994                 if (TocIDRequired(AH, depid) != 0)
17995                 {
17996                         /* Object will be dumped, so just reference it as a dependency */
17997                         if (*nDeps >= *allocDeps)
17998                         {
17999                                 *allocDeps *= 2;
18000                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18001                                                                                                           *allocDeps * sizeof(DumpId));
18002                         }
18003                         (*dependencies)[*nDeps] = depid;
18004                         (*nDeps)++;
18005                 }
18006                 else
18007                 {
18008                         /*
18009                          * Object will not be dumped, so recursively consider its deps. We
18010                          * rely on the assumption that sortDumpableObjects already broke
18011                          * any dependency loops, else we might recurse infinitely.
18012                          */
18013                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18014
18015                         if (otherdobj)
18016                                 findDumpableDependencies(AH, otherdobj,
18017                                                                                  dependencies, nDeps, allocDeps);
18018                 }
18019         }
18020 }
18021
18022
18023 /*
18024  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18025  * given type OID.
18026  *
18027  * This does not guarantee to schema-qualify the output, so it should not
18028  * be used to create the target object name for CREATE or ALTER commands.
18029  *
18030  * TODO: there might be some value in caching the results.
18031  */
18032 static char *
18033 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18034 {
18035         char       *result;
18036         PQExpBuffer query;
18037         PGresult   *res;
18038
18039         if (oid == 0)
18040         {
18041                 if ((opts & zeroAsOpaque) != 0)
18042                         return pg_strdup(g_opaque_type);
18043                 else if ((opts & zeroAsAny) != 0)
18044                         return pg_strdup("'any'");
18045                 else if ((opts & zeroAsStar) != 0)
18046                         return pg_strdup("*");
18047                 else if ((opts & zeroAsNone) != 0)
18048                         return pg_strdup("NONE");
18049         }
18050
18051         query = createPQExpBuffer();
18052         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18053                                           oid);
18054
18055         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18056
18057         /* result of format_type is already quoted */
18058         result = pg_strdup(PQgetvalue(res, 0, 0));
18059
18060         PQclear(res);
18061         destroyPQExpBuffer(query);
18062
18063         return result;
18064 }
18065
18066 /*
18067  * Return a column list clause for the given relation.
18068  *
18069  * Special case: if there are no undropped columns in the relation, return
18070  * "", not an invalid "()" column list.
18071  */
18072 static const char *
18073 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18074 {
18075         int                     numatts = ti->numatts;
18076         char      **attnames = ti->attnames;
18077         bool       *attisdropped = ti->attisdropped;
18078         bool            needComma;
18079         int                     i;
18080
18081         appendPQExpBufferChar(buffer, '(');
18082         needComma = false;
18083         for (i = 0; i < numatts; i++)
18084         {
18085                 if (attisdropped[i])
18086                         continue;
18087                 if (needComma)
18088                         appendPQExpBufferStr(buffer, ", ");
18089                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18090                 needComma = true;
18091         }
18092
18093         if (!needComma)
18094                 return "";                              /* no undropped columns */
18095
18096         appendPQExpBufferChar(buffer, ')');
18097         return buffer->data;
18098 }
18099
18100 /*
18101  * Check if a reloptions array is nonempty.
18102  */
18103 static bool
18104 nonemptyReloptions(const char *reloptions)
18105 {
18106         /* Don't want to print it if it's just "{}" */
18107         return (reloptions != NULL && strlen(reloptions) > 2);
18108 }
18109
18110 /*
18111  * Format a reloptions array and append it to the given buffer.
18112  *
18113  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18114  */
18115 static void
18116 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18117                                                 const char *prefix, Archive *fout)
18118 {
18119         bool            res;
18120
18121         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18122                                                                 fout->std_strings);
18123         if (!res)
18124                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
18125 }