]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Avoid using unsafe search_path settings during dump and restore.
[postgresql] / src / bin / pg_dump / pg_dump.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *        pg_dump is a utility for dumping out a postgres database
5  *        into a script file.
6  *
7  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to look at
18  *      the currently committed state.  So it is possible to get 'cache
19  *      lookup failed' error if someone performs DDL changes while a dump is
20  *      happening. The window for this sort of thing is from the acquisition
21  *      of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *      AccessShareLock on every table it intends to dump). It isn't very large,
23  *      but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres_fe.h"
33
34 #include <unistd.h>
35 #include <ctype.h>
36 #ifdef HAVE_TERMIOS_H
37 #include <termios.h>
38 #endif
39
40 #include "getopt_long.h"
41
42 #include "access/attnum.h"
43 #include "access/sysattr.h"
44 #include "access/transam.h"
45 #include "catalog/pg_aggregate.h"
46 #include "catalog/pg_am.h"
47 #include "catalog/pg_attribute.h"
48 #include "catalog/pg_cast.h"
49 #include "catalog/pg_class.h"
50 #include "catalog/pg_default_acl.h"
51 #include "catalog/pg_largeobject.h"
52 #include "catalog/pg_largeobject_metadata.h"
53 #include "catalog/pg_proc.h"
54 #include "catalog/pg_trigger.h"
55 #include "catalog/pg_type.h"
56 #include "libpq/libpq-fs.h"
57
58 #include "dumputils.h"
59 #include "parallel.h"
60 #include "pg_backup_db.h"
61 #include "pg_backup_utils.h"
62 #include "pg_dump.h"
63 #include "fe_utils/string_utils.h"
64
65
66 typedef struct
67 {
68         const char *descr;                      /* comment for an object */
69         Oid                     classoid;               /* object class (catalog OID) */
70         Oid                     objoid;                 /* object OID */
71         int                     objsubid;               /* subobject (table column #) */
72 } CommentItem;
73
74 typedef struct
75 {
76         const char *provider;           /* label provider of this security label */
77         const char *label;                      /* security label for an object */
78         Oid                     classoid;               /* object class (catalog OID) */
79         Oid                     objoid;                 /* object OID */
80         int                     objsubid;               /* subobject (table column #) */
81 } SecLabelItem;
82
83 typedef enum OidOptions
84 {
85         zeroAsOpaque = 1,
86         zeroAsAny = 2,
87         zeroAsStar = 4,
88         zeroAsNone = 8
89 } OidOptions;
90
91 /* global decls */
92 bool            g_verbose;                      /* User wants verbose narration of our
93                                                                  * activities. */
94 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
95
96 /* subquery used to convert user ID (eg, datdba) to user name */
97 static const char *username_subquery;
98
99 /*
100  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
101  * FirstNormalObjectId - 1.
102  */
103 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
104
105 /* The specified names/patterns should to match at least one entity */
106 static int      strict_names = 0;
107
108 /*
109  * Object inclusion/exclusion lists
110  *
111  * The string lists record the patterns given by command-line switches,
112  * which we then convert to lists of OIDs of matching objects.
113  */
114 static SimpleStringList schema_include_patterns = {NULL, NULL};
115 static SimpleOidList schema_include_oids = {NULL, NULL};
116 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
117 static SimpleOidList schema_exclude_oids = {NULL, NULL};
118
119 static SimpleStringList table_include_patterns = {NULL, NULL};
120 static SimpleOidList table_include_oids = {NULL, NULL};
121 static SimpleStringList table_exclude_patterns = {NULL, NULL};
122 static SimpleOidList table_exclude_oids = {NULL, NULL};
123 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
124 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
125
126
127 char            g_opaque_type[10];      /* name for the opaque type */
128
129 /* placeholders for the delimiters for comments */
130 char            g_comment_start[10];
131 char            g_comment_end[10];
132
133 static const CatalogId nilCatalogId = {0, 0};
134
135 /*
136  * Macro for producing quoted, schema-qualified name of a dumpable object.
137  * Note implicit dependence on "fout"; we should get rid of that argument.
138  */
139 #define fmtQualifiedDumpable(obj) \
140         fmtQualifiedId(fout->remoteVersion, \
141                                    (obj)->dobj.namespace->dobj.name, \
142                                    (obj)->dobj.name)
143
144 static void help(const char *progname);
145 static void setup_connection(Archive *AH,
146                                  const char *dumpencoding, const char *dumpsnapshot,
147                                  char *use_role);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(Archive *fout,
150                                                         SimpleStringList *patterns,
151                                                         SimpleOidList *oids,
152                                                         bool strict_names);
153 static void expand_table_name_patterns(Archive *fout,
154                                                    SimpleStringList *patterns,
155                                                    SimpleOidList *oids,
156                                                    bool strict_names);
157 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
158 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
159 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
160 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
161 static void dumpComment(Archive *fout, const char *type, const char *name,
162                         const char *namespace, const char *owner,
163                         CatalogId catalogId, int subid, DumpId dumpId);
164 static int findComments(Archive *fout, Oid classoid, Oid objoid,
165                          CommentItem **items);
166 static int      collectComments(Archive *fout, CommentItem **items);
167 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
168                          const char *namespace, const char *owner,
169                          CatalogId catalogId, int subid, DumpId dumpId);
170 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
171                           SecLabelItem **items);
172 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
173 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
174 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
175 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
176 static void dumpType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
179 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
181 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
182 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
183 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
184 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
185 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
186 static void dumpFunc(Archive *fout, FuncInfo *finfo);
187 static void dumpCast(Archive *fout, CastInfo *cast);
188 static void dumpTransform(Archive *fout, TransformInfo *transform);
189 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
190 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
191 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
192 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
193 static void dumpCollation(Archive *fout, CollInfo *collinfo);
194 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
195 static void dumpRule(Archive *fout, RuleInfo *rinfo);
196 static void dumpAgg(Archive *fout, AggInfo *agginfo);
197 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
198 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
199 static void dumpTable(Archive *fout, TableInfo *tbinfo);
200 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
201 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
202 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
203 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
204 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
205 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
206 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
207 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
208 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
209 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
210 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
211 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
212 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
213 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
214 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
215 static void dumpUserMappings(Archive *fout,
216                                  const char *servername, const char *namespace,
217                                  const char *owner, CatalogId catalogId, DumpId dumpId);
218 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
219
220 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
221                 const char *type, const char *name, const char *subname,
222                 const char *nspname, const char *owner,
223                 const char *acls, const char *racls,
224                 const char *initacls, const char *initracls);
225
226 static void getDependencies(Archive *fout);
227 static void BuildArchiveDependencies(Archive *fout);
228 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
229                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
230
231 static DumpableObject *createBoundaryObjects(void);
232 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
233                                                 DumpableObject *boundaryObjs);
234
235 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
236 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind);
237 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
238 static void buildMatViewRefreshDependencies(Archive *fout);
239 static void getTableDataFKConstraints(void);
240 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
241                                                   bool is_agg);
242 static char *format_function_arguments_old(Archive *fout,
243                                                           FuncInfo *finfo, int nallargs,
244                                                           char **allargtypes,
245                                                           char **argmodes,
246                                                           char **argnames);
247 static char *format_function_signature(Archive *fout,
248                                                   FuncInfo *finfo, bool honor_quotes);
249 static char *convertRegProcReference(Archive *fout,
250                                                 const char *proc);
251 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
252 static char *convertTSFunction(Archive *fout, Oid funcOid);
253 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
254 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
255 static void getBlobs(Archive *fout);
256 static void dumpBlob(Archive *fout, BlobInfo *binfo);
257 static int      dumpBlobs(Archive *fout, void *arg);
258 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
259 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
260 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
261 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
262 static void dumpDatabase(Archive *AH);
263 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
264                                    const char *dbname, Oid dboid);
265 static void dumpEncoding(Archive *AH);
266 static void dumpStdStrings(Archive *AH);
267 static void dumpSearchPath(Archive *AH);
268 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
269                                                                                  PQExpBuffer upgrade_buffer,
270                                                                                  Oid pg_type_oid,
271                                                                                  bool force_array_type);
272 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
273                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
274 static void binary_upgrade_set_pg_class_oids(Archive *fout,
275                                                                  PQExpBuffer upgrade_buffer,
276                                                                  Oid pg_class_oid, bool is_index);
277 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
278                                                                 DumpableObject *dobj,
279                                                                 const char *objtype,
280                                                                 const char *objname,
281                                                                 const char *objnamespace);
282 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
283 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
284 static bool nonemptyReloptions(const char *reloptions);
285 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
286                                                 const char *prefix, Archive *fout);
287 static char *get_synchronized_snapshot(Archive *fout);
288 static void setupDumpWorker(Archive *AHX);
289 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
290
291
292 int
293 main(int argc, char **argv)
294 {
295         int                     c;
296         const char *filename = NULL;
297         const char *format = "p";
298         TableInfo  *tblinfo;
299         int                     numTables;
300         DumpableObject **dobjs;
301         int                     numObjs;
302         DumpableObject *boundaryObjs;
303         int                     i;
304         int                     optindex;
305         RestoreOptions *ropt;
306         Archive    *fout;                       /* the script file */
307         const char *dumpencoding = NULL;
308         const char *dumpsnapshot = NULL;
309         char       *use_role = NULL;
310         int                     numWorkers = 1;
311         trivalue        prompt_password = TRI_DEFAULT;
312         int                     compressLevel = -1;
313         int                     plainText = 0;
314         ArchiveFormat archiveFormat = archUnknown;
315         ArchiveMode archiveMode;
316
317         static DumpOptions dopt;
318
319         static struct option long_options[] = {
320                 {"data-only", no_argument, NULL, 'a'},
321                 {"blobs", no_argument, NULL, 'b'},
322                 {"no-blobs", no_argument, NULL, 'B'},
323                 {"clean", no_argument, NULL, 'c'},
324                 {"create", no_argument, NULL, 'C'},
325                 {"dbname", required_argument, NULL, 'd'},
326                 {"file", required_argument, NULL, 'f'},
327                 {"format", required_argument, NULL, 'F'},
328                 {"host", required_argument, NULL, 'h'},
329                 {"jobs", 1, NULL, 'j'},
330                 {"no-reconnect", no_argument, NULL, 'R'},
331                 {"oids", no_argument, NULL, 'o'},
332                 {"no-owner", no_argument, NULL, 'O'},
333                 {"port", required_argument, NULL, 'p'},
334                 {"schema", required_argument, NULL, 'n'},
335                 {"exclude-schema", required_argument, NULL, 'N'},
336                 {"schema-only", no_argument, NULL, 's'},
337                 {"superuser", required_argument, NULL, 'S'},
338                 {"table", required_argument, NULL, 't'},
339                 {"exclude-table", required_argument, NULL, 'T'},
340                 {"no-password", no_argument, NULL, 'w'},
341                 {"password", no_argument, NULL, 'W'},
342                 {"username", required_argument, NULL, 'U'},
343                 {"verbose", no_argument, NULL, 'v'},
344                 {"no-privileges", no_argument, NULL, 'x'},
345                 {"no-acl", no_argument, NULL, 'x'},
346                 {"compress", required_argument, NULL, 'Z'},
347                 {"encoding", required_argument, NULL, 'E'},
348                 {"help", no_argument, NULL, '?'},
349                 {"version", no_argument, NULL, 'V'},
350
351                 /*
352                  * the following options don't have an equivalent short option letter
353                  */
354                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
355                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
356                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
357                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
358                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
359                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
360                 {"exclude-table-data", required_argument, NULL, 4},
361                 {"if-exists", no_argument, &dopt.if_exists, 1},
362                 {"inserts", no_argument, &dopt.dump_inserts, 1},
363                 {"lock-wait-timeout", required_argument, NULL, 2},
364                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
365                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
366                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
367                 {"role", required_argument, NULL, 3},
368                 {"section", required_argument, NULL, 5},
369                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
370                 {"snapshot", required_argument, NULL, 6},
371                 {"strict-names", no_argument, &strict_names, 1},
372                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
373                 {"no-comments", no_argument, &dopt.no_comments, 1},
374                 {"no-publications", no_argument, &dopt.no_publications, 1},
375                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
376                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
377                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
378                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
379                 {"no-sync", no_argument, NULL, 7},
380
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':                       /* Dump oids */
475                                 dopt.oids = true;
476                                 break;
477
478                         case 'O':                       /* Don't reconnect to match owner */
479                                 dopt.outputNoOwner = 1;
480                                 break;
481
482                         case 'p':                       /* server port */
483                                 dopt.pgport = pg_strdup(optarg);
484                                 break;
485
486                         case 'R':
487                                 /* no-op, still accepted for backwards compatibility */
488                                 break;
489
490                         case 's':                       /* dump schema only */
491                                 dopt.schemaOnly = true;
492                                 break;
493
494                         case 'S':                       /* Username for superuser in plain text output */
495                                 dopt.outputSuperuser = pg_strdup(optarg);
496                                 break;
497
498                         case 't':                       /* include table(s) */
499                                 simple_string_list_append(&table_include_patterns, optarg);
500                                 dopt.include_everything = false;
501                                 break;
502
503                         case 'T':                       /* exclude table(s) */
504                                 simple_string_list_append(&table_exclude_patterns, optarg);
505                                 break;
506
507                         case 'U':
508                                 dopt.username = pg_strdup(optarg);
509                                 break;
510
511                         case 'v':                       /* verbose */
512                                 g_verbose = true;
513                                 break;
514
515                         case 'w':
516                                 prompt_password = TRI_NO;
517                                 break;
518
519                         case 'W':
520                                 prompt_password = TRI_YES;
521                                 break;
522
523                         case 'x':                       /* skip ACL dump */
524                                 dopt.aclsSkip = true;
525                                 break;
526
527                         case 'Z':                       /* Compression Level */
528                                 compressLevel = atoi(optarg);
529                                 if (compressLevel < 0 || compressLevel > 9)
530                                 {
531                                         write_msg(NULL, "compression level must be in range 0..9\n");
532                                         exit_nicely(1);
533                                 }
534                                 break;
535
536                         case 0:
537                                 /* This covers the long options. */
538                                 break;
539
540                         case 2:                         /* lock-wait-timeout */
541                                 dopt.lockWaitTimeout = pg_strdup(optarg);
542                                 break;
543
544                         case 3:                         /* SET ROLE */
545                                 use_role = pg_strdup(optarg);
546                                 break;
547
548                         case 4:                         /* exclude table(s) data */
549                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
550                                 break;
551
552                         case 5:                         /* section */
553                                 set_dump_section(optarg, &dopt.dumpSections);
554                                 break;
555
556                         case 6:                         /* snapshot */
557                                 dumpsnapshot = pg_strdup(optarg);
558                                 break;
559
560                         case 7:                         /* no-sync */
561                                 dosync = false;
562                                 break;
563
564                         default:
565                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
566                                 exit_nicely(1);
567                 }
568         }
569
570         /*
571          * Non-option argument specifies database name as long as it wasn't
572          * already specified with -d / --dbname
573          */
574         if (optind < argc && dopt.dbname == NULL)
575                 dopt.dbname = argv[optind++];
576
577         /* Complain if any arguments remain */
578         if (optind < argc)
579         {
580                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
581                                 progname, argv[optind]);
582                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
583                                 progname);
584                 exit_nicely(1);
585         }
586
587         /* --column-inserts implies --inserts */
588         if (dopt.column_inserts)
589                 dopt.dump_inserts = 1;
590
591         /*
592          * Binary upgrade mode implies dumping sequence data even in schema-only
593          * mode.  This is not exposed as a separate option, but kept separate
594          * internally for clarity.
595          */
596         if (dopt.binary_upgrade)
597                 dopt.sequence_data = 1;
598
599         if (dopt.dataOnly && dopt.schemaOnly)
600         {
601                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
602                 exit_nicely(1);
603         }
604
605         if (dopt.dataOnly && dopt.outputClean)
606         {
607                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
608                 exit_nicely(1);
609         }
610
611         if (dopt.dump_inserts && dopt.oids)
612         {
613                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
614                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
615                 exit_nicely(1);
616         }
617
618         if (dopt.if_exists && !dopt.outputClean)
619                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
620
621         /* Identify archive format to emit */
622         archiveFormat = parseArchiveFormat(format, &archiveMode);
623
624         /* archiveFormat specific setup */
625         if (archiveFormat == archNull)
626                 plainText = 1;
627
628         /* Custom and directory formats are compressed by default, others not */
629         if (compressLevel == -1)
630         {
631 #ifdef HAVE_LIBZ
632                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
633                         compressLevel = Z_DEFAULT_COMPRESSION;
634                 else
635 #endif
636                         compressLevel = 0;
637         }
638
639 #ifndef HAVE_LIBZ
640         if (compressLevel != 0)
641                 write_msg(NULL, "WARNING: requested compression not available in this "
642                                   "installation -- archive will be uncompressed\n");
643         compressLevel = 0;
644 #endif
645
646         /*
647          * If emitting an archive format, we always want to emit a DATABASE item,
648          * in case --create is specified at pg_restore time.
649          */
650         if (!plainText)
651                 dopt.outputCreateDB = 1;
652
653         /*
654          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
655          * parallel jobs because that's the maximum limit for the
656          * WaitForMultipleObjects() call.
657          */
658         if (numWorkers <= 0
659 #ifdef WIN32
660                 || numWorkers > MAXIMUM_WAIT_OBJECTS
661 #endif
662                 )
663                 exit_horribly(NULL, "invalid number of parallel jobs\n");
664
665         /* Parallel backup only in the directory archive format so far */
666         if (archiveFormat != archDirectory && numWorkers > 1)
667                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
668
669         /* Open the output file */
670         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
671                                                  archiveMode, setupDumpWorker);
672
673         /* Make dump options accessible right away */
674         SetArchiveOptions(fout, &dopt, NULL);
675
676         /* Register the cleanup hook */
677         on_exit_close_archive(fout);
678
679         /* Let the archiver know how noisy to be */
680         fout->verbose = g_verbose;
681
682         /*
683          * We allow the server to be back to 8.0, and up to any minor release of
684          * our own major version.  (See also version check in pg_dumpall.c.)
685          */
686         fout->minRemoteVersion = 80000;
687         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
688
689         fout->numWorkers = numWorkers;
690
691         /*
692          * Open the database using the Archiver, so it knows about it. Errors mean
693          * death.
694          */
695         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
696         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
697
698         /*
699          * Disable security label support if server version < v9.1.x (prevents
700          * access to nonexistent pg_seclabel catalog)
701          */
702         if (fout->remoteVersion < 90100)
703                 dopt.no_security_labels = 1;
704
705         /*
706          * On hot standbys, never try to dump unlogged table data, since it will
707          * just throw an error.
708          */
709         if (fout->isStandby)
710                 dopt.no_unlogged_table_data = true;
711
712         /* Select the appropriate subquery to convert user IDs to names */
713         if (fout->remoteVersion >= 80100)
714                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
715         else
716                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
717
718         /* check the version for the synchronized snapshots feature */
719         if (numWorkers > 1 && fout->remoteVersion < 90200
720                 && !dopt.no_synchronized_snapshots)
721                 exit_horribly(NULL,
722                                           "Synchronized snapshots are not supported by this server version.\n"
723                                           "Run with --no-synchronized-snapshots instead if you do not need\n"
724                                           "synchronized snapshots.\n");
725
726         /* check the version when a snapshot is explicitly specified by user */
727         if (dumpsnapshot && fout->remoteVersion < 90200)
728                 exit_horribly(NULL,
729                                           "Exported snapshots are not supported by this server version.\n");
730
731         /*
732          * Find the last built-in OID, if needed (prior to 8.1)
733          *
734          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
735          */
736         if (fout->remoteVersion < 80100)
737                 g_last_builtin_oid = findLastBuiltinOid_V71(fout,
738                                                                                                         PQdb(GetConnection(fout)));
739         else
740                 g_last_builtin_oid = FirstNormalObjectId - 1;
741
742         if (g_verbose)
743                 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
744
745         /* Expand schema selection patterns into OID lists */
746         if (schema_include_patterns.head != NULL)
747         {
748                 expand_schema_name_patterns(fout, &schema_include_patterns,
749                                                                         &schema_include_oids,
750                                                                         strict_names);
751                 if (schema_include_oids.head == NULL)
752                         exit_horribly(NULL, "no matching schemas were found\n");
753         }
754         expand_schema_name_patterns(fout, &schema_exclude_patterns,
755                                                                 &schema_exclude_oids,
756                                                                 false);
757         /* non-matching exclusion patterns aren't an error */
758
759         /* Expand table selection patterns into OID lists */
760         if (table_include_patterns.head != NULL)
761         {
762                 expand_table_name_patterns(fout, &table_include_patterns,
763                                                                    &table_include_oids,
764                                                                    strict_names);
765                 if (table_include_oids.head == NULL)
766                         exit_horribly(NULL, "no matching tables were found\n");
767         }
768         expand_table_name_patterns(fout, &table_exclude_patterns,
769                                                            &table_exclude_oids,
770                                                            false);
771
772         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
773                                                            &tabledata_exclude_oids,
774                                                            false);
775
776         /* non-matching exclusion patterns aren't an error */
777
778         /*
779          * Dumping blobs is the default for dumps where an inclusion switch is not
780          * used (an "include everything" dump).  -B can be used to exclude blobs
781          * from those dumps.  -b can be used to include blobs even when an
782          * inclusion switch is used.
783          *
784          * -s means "schema only" and blobs are data, not schema, so we never
785          * include blobs when -s is used.
786          */
787         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
788                 dopt.outputBlobs = true;
789
790         /*
791          * Now scan the database and create DumpableObject structs for all the
792          * objects we intend to dump.
793          */
794         tblinfo = getSchemaData(fout, &numTables);
795
796         if (fout->remoteVersion < 80400)
797                 guessConstraintInheritance(tblinfo, numTables);
798
799         if (!dopt.schemaOnly)
800         {
801                 getTableData(&dopt, tblinfo, numTables, dopt.oids, 0);
802                 buildMatViewRefreshDependencies(fout);
803                 if (dopt.dataOnly)
804                         getTableDataFKConstraints();
805         }
806
807         if (dopt.schemaOnly && dopt.sequence_data)
808                 getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE);
809
810         /*
811          * In binary-upgrade mode, we do not have to worry about the actual blob
812          * data or the associated metadata that resides in the pg_largeobject and
813          * pg_largeobject_metadata tables, respectivly.
814          *
815          * However, we do need to collect blob information as there may be
816          * comments or other information on blobs that we do need to dump out.
817          */
818         if (dopt.outputBlobs || dopt.binary_upgrade)
819                 getBlobs(fout);
820
821         /*
822          * Collect dependency data to assist in ordering the objects.
823          */
824         getDependencies(fout);
825
826         /* Lastly, create dummy objects to represent the section boundaries */
827         boundaryObjs = createBoundaryObjects();
828
829         /* Get pointers to all the known DumpableObjects */
830         getDumpableObjects(&dobjs, &numObjs);
831
832         /*
833          * Add dummy dependencies to enforce the dump section ordering.
834          */
835         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
836
837         /*
838          * Sort the objects into a safe dump order (no forward references).
839          *
840          * We rely on dependency information to help us determine a safe order, so
841          * the initial sort is mostly for cosmetic purposes: we sort by name to
842          * ensure that logically identical schemas will dump identically.
843          */
844         sortDumpableObjectsByTypeName(dobjs, numObjs);
845
846         /* If we do a parallel dump, we want the largest tables to go first */
847         if (archiveFormat == archDirectory && numWorkers > 1)
848                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
849
850         sortDumpableObjects(dobjs, numObjs,
851                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
852
853         /*
854          * Create archive TOC entries for all the objects to be dumped, in a safe
855          * order.
856          */
857
858         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
859         dumpEncoding(fout);
860         dumpStdStrings(fout);
861         dumpSearchPath(fout);
862
863         /* The database items are always next, unless we don't want them at all */
864         if (dopt.outputCreateDB)
865                 dumpDatabase(fout);
866
867         /* Now the rearrangeable objects. */
868         for (i = 0; i < numObjs; i++)
869                 dumpDumpableObject(fout, dobjs[i]);
870
871         /*
872          * Set up options info to ensure we dump what we want.
873          */
874         ropt = NewRestoreOptions();
875         ropt->filename = filename;
876
877         /* if you change this list, see dumpOptionsFromRestoreOptions */
878         ropt->dropSchema = dopt.outputClean;
879         ropt->dataOnly = dopt.dataOnly;
880         ropt->schemaOnly = dopt.schemaOnly;
881         ropt->if_exists = dopt.if_exists;
882         ropt->column_inserts = dopt.column_inserts;
883         ropt->dumpSections = dopt.dumpSections;
884         ropt->aclsSkip = dopt.aclsSkip;
885         ropt->superuser = dopt.outputSuperuser;
886         ropt->createDB = dopt.outputCreateDB;
887         ropt->noOwner = dopt.outputNoOwner;
888         ropt->noTablespace = dopt.outputNoTablespaces;
889         ropt->disable_triggers = dopt.disable_triggers;
890         ropt->use_setsessauth = dopt.use_setsessauth;
891         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
892         ropt->dump_inserts = dopt.dump_inserts;
893         ropt->no_comments = dopt.no_comments;
894         ropt->no_publications = dopt.no_publications;
895         ropt->no_security_labels = dopt.no_security_labels;
896         ropt->no_subscriptions = dopt.no_subscriptions;
897         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
898         ropt->include_everything = dopt.include_everything;
899         ropt->enable_row_security = dopt.enable_row_security;
900         ropt->sequence_data = dopt.sequence_data;
901         ropt->binary_upgrade = dopt.binary_upgrade;
902
903         if (compressLevel == -1)
904                 ropt->compression = 0;
905         else
906                 ropt->compression = compressLevel;
907
908         ropt->suppressDumpWarnings = true;      /* We've already shown them */
909
910         SetArchiveOptions(fout, &dopt, ropt);
911
912         /* Mark which entries should be output */
913         ProcessArchiveRestoreOptions(fout);
914
915         /*
916          * The archive's TOC entries are now marked as to which ones will actually
917          * be output, so we can set up their dependency lists properly. This isn't
918          * necessary for plain-text output, though.
919          */
920         if (!plainText)
921                 BuildArchiveDependencies(fout);
922
923         /*
924          * And finally we can do the actual output.
925          *
926          * Note: for non-plain-text output formats, the output file is written
927          * inside CloseArchive().  This is, um, bizarre; but not worth changing
928          * right now.
929          */
930         if (plainText)
931                 RestoreArchive(fout);
932
933         CloseArchive(fout);
934
935         exit_nicely(0);
936 }
937
938
939 static void
940 help(const char *progname)
941 {
942         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
943         printf(_("Usage:\n"));
944         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
945
946         printf(_("\nGeneral options:\n"));
947         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
948         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
949                          "                               plain text (default))\n"));
950         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
951         printf(_("  -v, --verbose                verbose mode\n"));
952         printf(_("  -V, --version                output version information, then exit\n"));
953         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
954         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
955         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
956         printf(_("  -?, --help                   show this help, then exit\n"));
957
958         printf(_("\nOptions controlling the output content:\n"));
959         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
960         printf(_("  -b, --blobs                  include large objects in dump\n"));
961         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
962         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
963         printf(_("  -C, --create                 include commands to create database in dump\n"));
964         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
965         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
966         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
967         printf(_("  -o, --oids                   include OIDs in dump\n"));
968         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
969                          "                               plain-text format\n"));
970         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
971         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
972         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
973         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
974         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
975         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
976         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
977         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
978         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
979         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
980                          "                               access to)\n"));
981         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
982         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
983         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
984         printf(_("  --no-comments                do not dump comments\n"));
985         printf(_("  --no-publications            do not dump publications\n"));
986         printf(_("  --no-security-labels         do not dump security label assignments\n"));
987         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
988         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
989         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
990         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
991         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
992         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
993         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
994         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
995         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
996         printf(_("  --strict-names               require table and/or schema include patterns to\n"
997                          "                               match at least one entity each\n"));
998         printf(_("  --use-set-session-authorization\n"
999                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1000                          "                               ALTER OWNER commands to set ownership\n"));
1001
1002         printf(_("\nConnection options:\n"));
1003         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1004         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1005         printf(_("  -p, --port=PORT          database server port number\n"));
1006         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1007         printf(_("  -w, --no-password        never prompt for password\n"));
1008         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1009         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1010
1011         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1012                          "variable value is used.\n\n"));
1013         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1014 }
1015
1016 static void
1017 setup_connection(Archive *AH, const char *dumpencoding,
1018                                  const char *dumpsnapshot, char *use_role)
1019 {
1020         DumpOptions *dopt = AH->dopt;
1021         PGconn     *conn = GetConnection(AH);
1022         const char *std_strings;
1023
1024         /*
1025          * Set the client encoding if requested.
1026          */
1027         if (dumpencoding)
1028         {
1029                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1030                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1031                                                   dumpencoding);
1032         }
1033
1034         /*
1035          * Get the active encoding and the standard_conforming_strings setting, so
1036          * we know how to escape strings.
1037          */
1038         AH->encoding = PQclientEncoding(conn);
1039
1040         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1041         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1042
1043         /*
1044          * Set the role if requested.  In a parallel dump worker, we'll be passed
1045          * use_role == NULL, but AH->use_role is already set (if user specified it
1046          * originally) and we should use that.
1047          */
1048         if (!use_role && AH->use_role)
1049                 use_role = AH->use_role;
1050
1051         /* Set the role if requested */
1052         if (use_role && AH->remoteVersion >= 80100)
1053         {
1054                 PQExpBuffer query = createPQExpBuffer();
1055
1056                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1057                 ExecuteSqlStatement(AH, query->data);
1058                 destroyPQExpBuffer(query);
1059
1060                 /* save it for possible later use by parallel workers */
1061                 if (!AH->use_role)
1062                         AH->use_role = pg_strdup(use_role);
1063         }
1064
1065         /* Set the datestyle to ISO to ensure the dump's portability */
1066         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1067
1068         /* Likewise, avoid using sql_standard intervalstyle */
1069         if (AH->remoteVersion >= 80400)
1070                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1071
1072         /*
1073          * Set extra_float_digits so that we can dump float data exactly (given
1074          * correctly implemented float I/O code, anyway)
1075          */
1076         if (AH->remoteVersion >= 90000)
1077                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1078         else
1079                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1080
1081         /*
1082          * If synchronized scanning is supported, disable it, to prevent
1083          * unpredictable changes in row ordering across a dump and reload.
1084          */
1085         if (AH->remoteVersion >= 80300)
1086                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1087
1088         /*
1089          * Disable timeouts if supported.
1090          */
1091         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1092         if (AH->remoteVersion >= 90300)
1093                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1094         if (AH->remoteVersion >= 90600)
1095                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1096
1097         /*
1098          * Quote all identifiers, if requested.
1099          */
1100         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1101                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1102
1103         /*
1104          * Adjust row-security mode, if supported.
1105          */
1106         if (AH->remoteVersion >= 90500)
1107         {
1108                 if (dopt->enable_row_security)
1109                         ExecuteSqlStatement(AH, "SET row_security = on");
1110                 else
1111                         ExecuteSqlStatement(AH, "SET row_security = off");
1112         }
1113
1114         /*
1115          * Start transaction-snapshot mode transaction to dump consistent data.
1116          */
1117         ExecuteSqlStatement(AH, "BEGIN");
1118         if (AH->remoteVersion >= 90100)
1119         {
1120                 /*
1121                  * To support the combination of serializable_deferrable with the jobs
1122                  * option we use REPEATABLE READ for the worker connections that are
1123                  * passed a snapshot.  As long as the snapshot is acquired in a
1124                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1125                  * REPEATABLE READ transaction provides the appropriate integrity
1126                  * guarantees.  This is a kluge, but safe for back-patching.
1127                  */
1128                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1129                         ExecuteSqlStatement(AH,
1130                                                                 "SET TRANSACTION ISOLATION LEVEL "
1131                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1132                 else
1133                         ExecuteSqlStatement(AH,
1134                                                                 "SET TRANSACTION ISOLATION LEVEL "
1135                                                                 "REPEATABLE READ, READ ONLY");
1136         }
1137         else
1138         {
1139                 ExecuteSqlStatement(AH,
1140                                                         "SET TRANSACTION ISOLATION LEVEL "
1141                                                         "SERIALIZABLE, READ ONLY");
1142         }
1143
1144         /*
1145          * If user specified a snapshot to use, select that.  In a parallel dump
1146          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1147          * is already set (if the server can handle it) and we should use that.
1148          */
1149         if (dumpsnapshot)
1150                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1151
1152         if (AH->sync_snapshot_id)
1153         {
1154                 PQExpBuffer query = createPQExpBuffer();
1155
1156                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1157                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1158                 ExecuteSqlStatement(AH, query->data);
1159                 destroyPQExpBuffer(query);
1160         }
1161         else if (AH->numWorkers > 1 &&
1162                          AH->remoteVersion >= 90200 &&
1163                          !dopt->no_synchronized_snapshots)
1164         {
1165                 if (AH->isStandby && AH->remoteVersion < 100000)
1166                         exit_horribly(NULL,
1167                                                   "Synchronized snapshots on standby servers are not supported by this server version.\n"
1168                                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1169                                                   "synchronized snapshots.\n");
1170
1171
1172                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1173         }
1174 }
1175
1176 /* Set up connection for a parallel worker process */
1177 static void
1178 setupDumpWorker(Archive *AH)
1179 {
1180         /*
1181          * We want to re-select all the same values the master connection is
1182          * using.  We'll have inherited directly-usable values in
1183          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1184          * inherited encoding value back to a string to pass to setup_connection.
1185          */
1186         setup_connection(AH,
1187                                          pg_encoding_to_char(AH->encoding),
1188                                          NULL,
1189                                          NULL);
1190 }
1191
1192 static char *
1193 get_synchronized_snapshot(Archive *fout)
1194 {
1195         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1196         char       *result;
1197         PGresult   *res;
1198
1199         res = ExecuteSqlQueryForSingleRow(fout, query);
1200         result = pg_strdup(PQgetvalue(res, 0, 0));
1201         PQclear(res);
1202
1203         return result;
1204 }
1205
1206 static ArchiveFormat
1207 parseArchiveFormat(const char *format, ArchiveMode *mode)
1208 {
1209         ArchiveFormat archiveFormat;
1210
1211         *mode = archModeWrite;
1212
1213         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1214         {
1215                 /* This is used by pg_dumpall, and is not documented */
1216                 archiveFormat = archNull;
1217                 *mode = archModeAppend;
1218         }
1219         else if (pg_strcasecmp(format, "c") == 0)
1220                 archiveFormat = archCustom;
1221         else if (pg_strcasecmp(format, "custom") == 0)
1222                 archiveFormat = archCustom;
1223         else if (pg_strcasecmp(format, "d") == 0)
1224                 archiveFormat = archDirectory;
1225         else if (pg_strcasecmp(format, "directory") == 0)
1226                 archiveFormat = archDirectory;
1227         else if (pg_strcasecmp(format, "p") == 0)
1228                 archiveFormat = archNull;
1229         else if (pg_strcasecmp(format, "plain") == 0)
1230                 archiveFormat = archNull;
1231         else if (pg_strcasecmp(format, "t") == 0)
1232                 archiveFormat = archTar;
1233         else if (pg_strcasecmp(format, "tar") == 0)
1234                 archiveFormat = archTar;
1235         else
1236                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1237         return archiveFormat;
1238 }
1239
1240 /*
1241  * Find the OIDs of all schemas matching the given list of patterns,
1242  * and append them to the given OID list.
1243  */
1244 static void
1245 expand_schema_name_patterns(Archive *fout,
1246                                                         SimpleStringList *patterns,
1247                                                         SimpleOidList *oids,
1248                                                         bool strict_names)
1249 {
1250         PQExpBuffer query;
1251         PGresult   *res;
1252         SimpleStringListCell *cell;
1253         int                     i;
1254
1255         if (patterns->head == NULL)
1256                 return;                                 /* nothing to do */
1257
1258         query = createPQExpBuffer();
1259
1260         /*
1261          * The loop below runs multiple SELECTs might sometimes result in
1262          * duplicate entries in the OID list, but we don't care.
1263          */
1264
1265         for (cell = patterns->head; cell; cell = cell->next)
1266         {
1267                 appendPQExpBuffer(query,
1268                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1269                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1270                                                           false, NULL, "n.nspname", NULL, NULL);
1271
1272                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1273                 if (strict_names && PQntuples(res) == 0)
1274                         exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1275
1276                 for (i = 0; i < PQntuples(res); i++)
1277                 {
1278                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1279                 }
1280
1281                 PQclear(res);
1282                 resetPQExpBuffer(query);
1283         }
1284
1285         destroyPQExpBuffer(query);
1286 }
1287
1288 /*
1289  * Find the OIDs of all tables matching the given list of patterns,
1290  * and append them to the given OID list.
1291  */
1292 static void
1293 expand_table_name_patterns(Archive *fout,
1294                                                    SimpleStringList *patterns, SimpleOidList *oids,
1295                                                    bool strict_names)
1296 {
1297         PQExpBuffer query;
1298         PGresult   *res;
1299         SimpleStringListCell *cell;
1300         int                     i;
1301
1302         if (patterns->head == NULL)
1303                 return;                                 /* nothing to do */
1304
1305         query = createPQExpBuffer();
1306
1307         /*
1308          * this might sometimes result in duplicate entries in the OID list, but
1309          * we don't care.
1310          */
1311
1312         for (cell = patterns->head; cell; cell = cell->next)
1313         {
1314                 appendPQExpBuffer(query,
1315                                                   "SELECT c.oid"
1316                                                   "\nFROM pg_catalog.pg_class c"
1317                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1318                                                   "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c')\n",
1319                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1320                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1321                                                   RELKIND_PARTITIONED_TABLE);
1322                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1323                                                           false, "n.nspname", "c.relname", NULL,
1324                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1325
1326                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1327                 if (strict_names && PQntuples(res) == 0)
1328                         exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1329
1330                 for (i = 0; i < PQntuples(res); i++)
1331                 {
1332                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1333                 }
1334
1335                 PQclear(res);
1336                 resetPQExpBuffer(query);
1337         }
1338
1339         destroyPQExpBuffer(query);
1340 }
1341
1342 /*
1343  * checkExtensionMembership
1344  *              Determine whether object is an extension member, and if so,
1345  *              record an appropriate dependency and set the object's dump flag.
1346  *
1347  * It's important to call this for each object that could be an extension
1348  * member.  Generally, we integrate this with determining the object's
1349  * to-be-dumped-ness, since extension membership overrides other rules for that.
1350  *
1351  * Returns true if object is an extension member, else false.
1352  */
1353 static bool
1354 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1355 {
1356         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1357
1358         if (ext == NULL)
1359                 return false;
1360
1361         dobj->ext_member = true;
1362
1363         /* Record dependency so that getDependencies needn't deal with that */
1364         addObjectDependency(dobj, ext->dobj.dumpId);
1365
1366         /*
1367          * In 9.6 and above, mark the member object to have any non-initial ACL,
1368          * policies, and security labels dumped.
1369          *
1370          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1371          * extract the information about the object.  We don't provide support for
1372          * initial policies and security labels and it seems unlikely for those to
1373          * ever exist, but we may have to revisit this later.
1374          *
1375          * Prior to 9.6, we do not include any extension member components.
1376          *
1377          * In binary upgrades, we still dump all components of the members
1378          * individually, since the idea is to exactly reproduce the database
1379          * contents rather than replace the extension contents with something
1380          * different.
1381          */
1382         if (fout->dopt->binary_upgrade)
1383                 dobj->dump = ext->dobj.dump;
1384         else
1385         {
1386                 if (fout->remoteVersion < 90600)
1387                         dobj->dump = DUMP_COMPONENT_NONE;
1388                 else
1389                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1390                                                                                                         DUMP_COMPONENT_SECLABEL |
1391                                                                                                         DUMP_COMPONENT_POLICY);
1392         }
1393
1394         return true;
1395 }
1396
1397 /*
1398  * selectDumpableNamespace: policy-setting subroutine
1399  *              Mark a namespace as to be dumped or not
1400  */
1401 static void
1402 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1403 {
1404         /*
1405          * If specific tables are being dumped, do not dump any complete
1406          * namespaces. If specific namespaces are being dumped, dump just those
1407          * namespaces. Otherwise, dump all non-system namespaces.
1408          */
1409         if (table_include_oids.head != NULL)
1410                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1411         else if (schema_include_oids.head != NULL)
1412                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1413                         simple_oid_list_member(&schema_include_oids,
1414                                                                    nsinfo->dobj.catId.oid) ?
1415                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1416         else if (fout->remoteVersion >= 90600 &&
1417                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1418         {
1419                 /*
1420                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1421                  * they are interesting (and not the original ACLs which were set at
1422                  * initdb time, see pg_init_privs).
1423                  */
1424                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1425         }
1426         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1427                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1428         {
1429                 /* Other system schemas don't get dumped */
1430                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1431         }
1432         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1433         {
1434                 /*
1435                  * The public schema is a strange beast that sits in a sort of
1436                  * no-mans-land between being a system object and a user object.  We
1437                  * don't want to dump creation or comment commands for it, because
1438                  * that complicates matters for non-superuser use of pg_dump.  But we
1439                  * should dump any ACL changes that have occurred for it, and of
1440                  * course we should dump contained objects.
1441                  */
1442                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1443                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1444         }
1445         else
1446                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1447
1448         /*
1449          * In any case, a namespace can be excluded by an exclusion switch
1450          */
1451         if (nsinfo->dobj.dump_contains &&
1452                 simple_oid_list_member(&schema_exclude_oids,
1453                                                            nsinfo->dobj.catId.oid))
1454                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1455
1456         /*
1457          * If the schema belongs to an extension, allow extension membership to
1458          * override the dump decision for the schema itself.  However, this does
1459          * not change dump_contains, so this won't change what we do with objects
1460          * within the schema.  (If they belong to the extension, they'll get
1461          * suppressed by it, otherwise not.)
1462          */
1463         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1464 }
1465
1466 /*
1467  * selectDumpableTable: policy-setting subroutine
1468  *              Mark a table as to be dumped or not
1469  */
1470 static void
1471 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1472 {
1473         if (checkExtensionMembership(&tbinfo->dobj, fout))
1474                 return;                                 /* extension membership overrides all else */
1475
1476         /*
1477          * If specific tables are being dumped, dump just those tables; else, dump
1478          * according to the parent namespace's dump flag.
1479          */
1480         if (table_include_oids.head != NULL)
1481                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1482                                                                                                    tbinfo->dobj.catId.oid) ?
1483                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1484         else
1485                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1486
1487         /*
1488          * In any case, a table can be excluded by an exclusion switch
1489          */
1490         if (tbinfo->dobj.dump &&
1491                 simple_oid_list_member(&table_exclude_oids,
1492                                                            tbinfo->dobj.catId.oid))
1493                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1494 }
1495
1496 /*
1497  * selectDumpableType: policy-setting subroutine
1498  *              Mark a type as to be dumped or not
1499  *
1500  * If it's a table's rowtype or an autogenerated array type, we also apply a
1501  * special type code to facilitate sorting into the desired order.  (We don't
1502  * want to consider those to be ordinary types because that would bring tables
1503  * up into the datatype part of the dump order.)  We still set the object's
1504  * dump flag; that's not going to cause the dummy type to be dumped, but we
1505  * need it so that casts involving such types will be dumped correctly -- see
1506  * dumpCast.  This means the flag should be set the same as for the underlying
1507  * object (the table or base type).
1508  */
1509 static void
1510 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1511 {
1512         /* skip complex types, except for standalone composite types */
1513         if (OidIsValid(tyinfo->typrelid) &&
1514                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1515         {
1516                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1517
1518                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1519                 if (tytable != NULL)
1520                         tyinfo->dobj.dump = tytable->dobj.dump;
1521                 else
1522                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1523                 return;
1524         }
1525
1526         /* skip auto-generated array types */
1527         if (tyinfo->isArray)
1528         {
1529                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1530
1531                 /*
1532                  * Fall through to set the dump flag; we assume that the subsequent
1533                  * rules will do the same thing as they would for the array's base
1534                  * type.  (We cannot reliably look up the base type here, since
1535                  * getTypes may not have processed it yet.)
1536                  */
1537         }
1538
1539         if (checkExtensionMembership(&tyinfo->dobj, fout))
1540                 return;                                 /* extension membership overrides all else */
1541
1542         /* Dump based on if the contents of the namespace are being dumped */
1543         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1544 }
1545
1546 /*
1547  * selectDumpableDefaultACL: policy-setting subroutine
1548  *              Mark a default ACL as to be dumped or not
1549  *
1550  * For per-schema default ACLs, dump if the schema is to be dumped.
1551  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1552  * and aclsSkip are checked separately.
1553  */
1554 static void
1555 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1556 {
1557         /* Default ACLs can't be extension members */
1558
1559         if (dinfo->dobj.namespace)
1560                 /* default ACLs are considered part of the namespace */
1561                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1562         else
1563                 dinfo->dobj.dump = dopt->include_everything ?
1564                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1565 }
1566
1567 /*
1568  * selectDumpableCast: policy-setting subroutine
1569  *              Mark a cast as to be dumped or not
1570  *
1571  * Casts do not belong to any particular namespace (since they haven't got
1572  * names), nor do they have identifiable owners.  To distinguish user-defined
1573  * casts from built-in ones, we must resort to checking whether the cast's
1574  * OID is in the range reserved for initdb.
1575  */
1576 static void
1577 selectDumpableCast(CastInfo *cast, Archive *fout)
1578 {
1579         if (checkExtensionMembership(&cast->dobj, fout))
1580                 return;                                 /* extension membership overrides all else */
1581
1582         /*
1583          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1584          * support ACLs currently.
1585          */
1586         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1587                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1588         else
1589                 cast->dobj.dump = fout->dopt->include_everything ?
1590                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1591 }
1592
1593 /*
1594  * selectDumpableProcLang: policy-setting subroutine
1595  *              Mark a procedural language as to be dumped or not
1596  *
1597  * Procedural languages do not belong to any particular namespace.  To
1598  * identify built-in languages, we must resort to checking whether the
1599  * language's OID is in the range reserved for initdb.
1600  */
1601 static void
1602 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1603 {
1604         if (checkExtensionMembership(&plang->dobj, fout))
1605                 return;                                 /* extension membership overrides all else */
1606
1607         /*
1608          * Only include procedural languages when we are dumping everything.
1609          *
1610          * For from-initdb procedural languages, only include ACLs, as we do for
1611          * the pg_catalog namespace.  We need this because procedural languages do
1612          * not live in any namespace.
1613          */
1614         if (!fout->dopt->include_everything)
1615                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1616         else
1617         {
1618                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1619                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1620                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1621                 else
1622                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1623         }
1624 }
1625
1626 /*
1627  * selectDumpableAccessMethod: policy-setting subroutine
1628  *              Mark an access method as to be dumped or not
1629  *
1630  * Access methods do not belong to any particular namespace.  To identify
1631  * built-in access methods, we must resort to checking whether the
1632  * method's OID is in the range reserved for initdb.
1633  */
1634 static void
1635 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1636 {
1637         if (checkExtensionMembership(&method->dobj, fout))
1638                 return;                                 /* extension membership overrides all else */
1639
1640         /*
1641          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1642          * they do not support ACLs currently.
1643          */
1644         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1645                 method->dobj.dump = DUMP_COMPONENT_NONE;
1646         else
1647                 method->dobj.dump = fout->dopt->include_everything ?
1648                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1649 }
1650
1651 /*
1652  * selectDumpableExtension: policy-setting subroutine
1653  *              Mark an extension as to be dumped or not
1654  *
1655  * Built-in extensions should be skipped except for checking ACLs, since we
1656  * assume those will already be installed in the target database.  We identify
1657  * such extensions by their having OIDs in the range reserved for initdb.
1658  * We dump all user-added extensions by default, or none of them if
1659  * include_everything is false (i.e., a --schema or --table switch was given).
1660  */
1661 static void
1662 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1663 {
1664         /*
1665          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1666          * change permissions on their member objects, if they wish to, and have
1667          * those changes preserved.
1668          */
1669         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1670                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1671         else
1672                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1673                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1674                         DUMP_COMPONENT_NONE;
1675 }
1676
1677 /*
1678  * selectDumpablePublicationTable: policy-setting subroutine
1679  *              Mark a publication table as to be dumped or not
1680  *
1681  * Publication tables have schemas, but those are ignored in decision making,
1682  * because publications are only dumped when we are dumping everything.
1683  */
1684 static void
1685 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1686 {
1687         if (checkExtensionMembership(dobj, fout))
1688                 return;                                 /* extension membership overrides all else */
1689
1690         dobj->dump = fout->dopt->include_everything ?
1691                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1692 }
1693
1694 /*
1695  * selectDumpableObject: policy-setting subroutine
1696  *              Mark a generic dumpable object as to be dumped or not
1697  *
1698  * Use this only for object types without a special-case routine above.
1699  */
1700 static void
1701 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1702 {
1703         if (checkExtensionMembership(dobj, fout))
1704                 return;                                 /* extension membership overrides all else */
1705
1706         /*
1707          * Default policy is to dump if parent namespace is dumpable, or for
1708          * non-namespace-associated items, dump if we're dumping "everything".
1709          */
1710         if (dobj->namespace)
1711                 dobj->dump = dobj->namespace->dobj.dump_contains;
1712         else
1713                 dobj->dump = fout->dopt->include_everything ?
1714                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1715 }
1716
1717 /*
1718  *      Dump a table's contents for loading using the COPY command
1719  *      - this routine is called by the Archiver when it wants the table
1720  *        to be dumped.
1721  */
1722
1723 static int
1724 dumpTableData_copy(Archive *fout, void *dcontext)
1725 {
1726         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1727         TableInfo  *tbinfo = tdinfo->tdtable;
1728         const char *classname = tbinfo->dobj.name;
1729         const bool      hasoids = tbinfo->hasoids;
1730         const bool      oids = tdinfo->oids;
1731         PQExpBuffer q = createPQExpBuffer();
1732
1733         /*
1734          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1735          * which uses it already.
1736          */
1737         PQExpBuffer clistBuf = createPQExpBuffer();
1738         PGconn     *conn = GetConnection(fout);
1739         PGresult   *res;
1740         int                     ret;
1741         char       *copybuf;
1742         const char *column_list;
1743
1744         if (g_verbose)
1745                 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1746                                   tbinfo->dobj.namespace->dobj.name, classname);
1747
1748         /*
1749          * Specify the column list explicitly so that we have no possibility of
1750          * retrieving data in the wrong column order.  (The default column
1751          * ordering of COPY will not be what we want in certain corner cases
1752          * involving ADD COLUMN and inheritance.)
1753          */
1754         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1755
1756         if (oids && hasoids)
1757         {
1758                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1759                                                   fmtQualifiedDumpable(tbinfo),
1760                                                   column_list);
1761         }
1762         else if (tdinfo->filtercond)
1763         {
1764                 /* Note: this syntax is only supported in 8.2 and up */
1765                 appendPQExpBufferStr(q, "COPY (SELECT ");
1766                 /* klugery to get rid of parens in column list */
1767                 if (strlen(column_list) > 2)
1768                 {
1769                         appendPQExpBufferStr(q, column_list + 1);
1770                         q->data[q->len - 1] = ' ';
1771                 }
1772                 else
1773                         appendPQExpBufferStr(q, "* ");
1774                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1775                                                   fmtQualifiedDumpable(tbinfo),
1776                                                   tdinfo->filtercond);
1777         }
1778         else
1779         {
1780                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1781                                                   fmtQualifiedDumpable(tbinfo),
1782                                                   column_list);
1783         }
1784         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1785         PQclear(res);
1786         destroyPQExpBuffer(clistBuf);
1787
1788         for (;;)
1789         {
1790                 ret = PQgetCopyData(conn, &copybuf, 0);
1791
1792                 if (ret < 0)
1793                         break;                          /* done or error */
1794
1795                 if (copybuf)
1796                 {
1797                         WriteData(fout, copybuf, ret);
1798                         PQfreemem(copybuf);
1799                 }
1800
1801                 /* ----------
1802                  * THROTTLE:
1803                  *
1804                  * There was considerable discussion in late July, 2000 regarding
1805                  * slowing down pg_dump when backing up large tables. Users with both
1806                  * slow & fast (multi-processor) machines experienced performance
1807                  * degradation when doing a backup.
1808                  *
1809                  * Initial attempts based on sleeping for a number of ms for each ms
1810                  * of work were deemed too complex, then a simple 'sleep in each loop'
1811                  * implementation was suggested. The latter failed because the loop
1812                  * was too tight. Finally, the following was implemented:
1813                  *
1814                  * If throttle is non-zero, then
1815                  *              See how long since the last sleep.
1816                  *              Work out how long to sleep (based on ratio).
1817                  *              If sleep is more than 100ms, then
1818                  *                      sleep
1819                  *                      reset timer
1820                  *              EndIf
1821                  * EndIf
1822                  *
1823                  * where the throttle value was the number of ms to sleep per ms of
1824                  * work. The calculation was done in each loop.
1825                  *
1826                  * Most of the hard work is done in the backend, and this solution
1827                  * still did not work particularly well: on slow machines, the ratio
1828                  * was 50:1, and on medium paced machines, 1:1, and on fast
1829                  * multi-processor machines, it had little or no effect, for reasons
1830                  * that were unclear.
1831                  *
1832                  * Further discussion ensued, and the proposal was dropped.
1833                  *
1834                  * For those people who want this feature, it can be implemented using
1835                  * gettimeofday in each loop, calculating the time since last sleep,
1836                  * multiplying that by the sleep ratio, then if the result is more
1837                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1838                  * function to sleep for a subsecond period ie.
1839                  *
1840                  * select(0, NULL, NULL, NULL, &tvi);
1841                  *
1842                  * This will return after the interval specified in the structure tvi.
1843                  * Finally, call gettimeofday again to save the 'last sleep time'.
1844                  * ----------
1845                  */
1846         }
1847         archprintf(fout, "\\.\n\n\n");
1848
1849         if (ret == -2)
1850         {
1851                 /* copy data transfer failed */
1852                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1853                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1854                 write_msg(NULL, "The command was: %s\n", q->data);
1855                 exit_nicely(1);
1856         }
1857
1858         /* Check command status and return to normal libpq state */
1859         res = PQgetResult(conn);
1860         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1861         {
1862                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1863                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1864                 write_msg(NULL, "The command was: %s\n", q->data);
1865                 exit_nicely(1);
1866         }
1867         PQclear(res);
1868
1869         /* Do this to ensure we've pumped libpq back to idle state */
1870         if (PQgetResult(conn) != NULL)
1871                 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1872                                   classname);
1873
1874         destroyPQExpBuffer(q);
1875         return 1;
1876 }
1877
1878 /*
1879  * Dump table data using INSERT commands.
1880  *
1881  * Caution: when we restore from an archive file direct to database, the
1882  * INSERT commands emitted by this function have to be parsed by
1883  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1884  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1885  */
1886 static int
1887 dumpTableData_insert(Archive *fout, void *dcontext)
1888 {
1889         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1890         TableInfo  *tbinfo = tdinfo->tdtable;
1891         DumpOptions *dopt = fout->dopt;
1892         PQExpBuffer q = createPQExpBuffer();
1893         PQExpBuffer insertStmt = NULL;
1894         PGresult   *res;
1895         int                     tuple;
1896         int                     nfields;
1897         int                     field;
1898
1899         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1900                                           "SELECT * FROM ONLY %s",
1901                                           fmtQualifiedDumpable(tbinfo));
1902         if (tdinfo->filtercond)
1903                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1904
1905         ExecuteSqlStatement(fout, q->data);
1906
1907         while (1)
1908         {
1909                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1910                                                           PGRES_TUPLES_OK);
1911                 nfields = PQnfields(res);
1912                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1913                 {
1914                         /*
1915                          * First time through, we build as much of the INSERT statement as
1916                          * possible in "insertStmt", which we can then just print for each
1917                          * line. If the table happens to have zero columns then this will
1918                          * be a complete statement, otherwise it will end in "VALUES(" and
1919                          * be ready to have the row's column values appended.
1920                          */
1921                         if (insertStmt == NULL)
1922                         {
1923                                 TableInfo  *targettab;
1924
1925                                 insertStmt = createPQExpBuffer();
1926
1927                                 /*
1928                                  * When load-via-partition-root is set, get the root table
1929                                  * name for the partition table, so that we can reload data
1930                                  * through the root table.
1931                                  */
1932                                 if (dopt->load_via_partition_root && tbinfo->ispartition)
1933                                         targettab = getRootTableInfo(tbinfo);
1934                                 else
1935                                         targettab = tbinfo;
1936
1937                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1938                                                                   fmtQualifiedDumpable(targettab));
1939
1940                                 /* corner case for zero-column table */
1941                                 if (nfields == 0)
1942                                 {
1943                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1944                                 }
1945                                 else
1946                                 {
1947                                         /* append the list of column names if required */
1948                                         if (dopt->column_inserts)
1949                                         {
1950                                                 appendPQExpBufferChar(insertStmt, '(');
1951                                                 for (field = 0; field < nfields; field++)
1952                                                 {
1953                                                         if (field > 0)
1954                                                                 appendPQExpBufferStr(insertStmt, ", ");
1955                                                         appendPQExpBufferStr(insertStmt,
1956                                                                                                  fmtId(PQfname(res, field)));
1957                                                 }
1958                                                 appendPQExpBufferStr(insertStmt, ") ");
1959                                         }
1960
1961                                         if (tbinfo->needs_override)
1962                                                 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1963
1964                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1965                                 }
1966                         }
1967
1968                         archputs(insertStmt->data, fout);
1969
1970                         /* if it is zero-column table then we're done */
1971                         if (nfields == 0)
1972                                 continue;
1973
1974                         for (field = 0; field < nfields; field++)
1975                         {
1976                                 if (field > 0)
1977                                         archputs(", ", fout);
1978                                 if (PQgetisnull(res, tuple, field))
1979                                 {
1980                                         archputs("NULL", fout);
1981                                         continue;
1982                                 }
1983
1984                                 /* XXX This code is partially duplicated in ruleutils.c */
1985                                 switch (PQftype(res, field))
1986                                 {
1987                                         case INT2OID:
1988                                         case INT4OID:
1989                                         case INT8OID:
1990                                         case OIDOID:
1991                                         case FLOAT4OID:
1992                                         case FLOAT8OID:
1993                                         case NUMERICOID:
1994                                                 {
1995                                                         /*
1996                                                          * These types are printed without quotes unless
1997                                                          * they contain values that aren't accepted by the
1998                                                          * scanner unquoted (e.g., 'NaN').  Note that
1999                                                          * strtod() and friends might accept NaN, so we
2000                                                          * can't use that to test.
2001                                                          *
2002                                                          * In reality we only need to defend against
2003                                                          * infinity and NaN, so we need not get too crazy
2004                                                          * about pattern matching here.
2005                                                          */
2006                                                         const char *s = PQgetvalue(res, tuple, field);
2007
2008                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2009                                                                 archputs(s, fout);
2010                                                         else
2011                                                                 archprintf(fout, "'%s'", s);
2012                                                 }
2013                                                 break;
2014
2015                                         case BITOID:
2016                                         case VARBITOID:
2017                                                 archprintf(fout, "B'%s'",
2018                                                                    PQgetvalue(res, tuple, field));
2019                                                 break;
2020
2021                                         case BOOLOID:
2022                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2023                                                         archputs("true", fout);
2024                                                 else
2025                                                         archputs("false", fout);
2026                                                 break;
2027
2028                                         default:
2029                                                 /* All other types are printed as string literals. */
2030                                                 resetPQExpBuffer(q);
2031                                                 appendStringLiteralAH(q,
2032                                                                                           PQgetvalue(res, tuple, field),
2033                                                                                           fout);
2034                                                 archputs(q->data, fout);
2035                                                 break;
2036                                 }
2037                         }
2038                         archputs(");\n", fout);
2039                 }
2040
2041                 if (PQntuples(res) <= 0)
2042                 {
2043                         PQclear(res);
2044                         break;
2045                 }
2046                 PQclear(res);
2047         }
2048
2049         archputs("\n\n", fout);
2050
2051         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2052
2053         destroyPQExpBuffer(q);
2054         if (insertStmt != NULL)
2055                 destroyPQExpBuffer(insertStmt);
2056
2057         return 1;
2058 }
2059
2060 /*
2061  * getRootTableInfo:
2062  *     get the root TableInfo for the given partition table.
2063  */
2064 static TableInfo *
2065 getRootTableInfo(TableInfo *tbinfo)
2066 {
2067         TableInfo  *parentTbinfo;
2068
2069         Assert(tbinfo->ispartition);
2070         Assert(tbinfo->numParents == 1);
2071
2072         parentTbinfo = tbinfo->parents[0];
2073         while (parentTbinfo->ispartition)
2074         {
2075                 Assert(parentTbinfo->numParents == 1);
2076                 parentTbinfo = parentTbinfo->parents[0];
2077         }
2078
2079         return parentTbinfo;
2080 }
2081
2082 /*
2083  * dumpTableData -
2084  *        dump the contents of a single table
2085  *
2086  * Actually, this just makes an ArchiveEntry for the table contents.
2087  */
2088 static void
2089 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2090 {
2091         DumpOptions *dopt = fout->dopt;
2092         TableInfo  *tbinfo = tdinfo->tdtable;
2093         PQExpBuffer copyBuf = createPQExpBuffer();
2094         PQExpBuffer clistBuf = createPQExpBuffer();
2095         DataDumperPtr dumpFn;
2096         char       *copyStmt;
2097         const char *copyFrom;
2098
2099         if (!dopt->dump_inserts)
2100         {
2101                 /* Dump/restore using COPY */
2102                 dumpFn = dumpTableData_copy;
2103
2104                 /*
2105                  * When load-via-partition-root is set, get the root table name for
2106                  * the partition table, so that we can reload data through the root
2107                  * table.
2108                  */
2109                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2110                 {
2111                         TableInfo  *parentTbinfo;
2112
2113                         parentTbinfo = getRootTableInfo(tbinfo);
2114                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2115                 }
2116                 else
2117                         copyFrom = fmtQualifiedDumpable(tbinfo);
2118
2119                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2120                 appendPQExpBuffer(copyBuf, "COPY %s ",
2121                                                   copyFrom);
2122                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
2123                                                   fmtCopyColumnList(tbinfo, clistBuf),
2124                                                   (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
2125                 copyStmt = copyBuf->data;
2126         }
2127         else
2128         {
2129                 /* Restore using INSERT */
2130                 dumpFn = dumpTableData_insert;
2131                 copyStmt = NULL;
2132         }
2133
2134         /*
2135          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2136          * dependency on its table as "special" and pass it to ArchiveEntry now.
2137          * See comments for BuildArchiveDependencies.
2138          */
2139         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2140                 ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2141                                          tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2142                                          NULL, tbinfo->rolname,
2143                                          false, "TABLE DATA", SECTION_DATA,
2144                                          "", "", copyStmt,
2145                                          &(tbinfo->dobj.dumpId), 1,
2146                                          dumpFn, tdinfo);
2147
2148         destroyPQExpBuffer(copyBuf);
2149         destroyPQExpBuffer(clistBuf);
2150 }
2151
2152 /*
2153  * refreshMatViewData -
2154  *        load or refresh the contents of a single materialized view
2155  *
2156  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2157  * statement.
2158  */
2159 static void
2160 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2161 {
2162         TableInfo  *tbinfo = tdinfo->tdtable;
2163         PQExpBuffer q;
2164
2165         /* If the materialized view is not flagged as populated, skip this. */
2166         if (!tbinfo->relispopulated)
2167                 return;
2168
2169         q = createPQExpBuffer();
2170
2171         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2172                                           fmtQualifiedDumpable(tbinfo));
2173
2174         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2175                 ArchiveEntry(fout,
2176                                          tdinfo->dobj.catId,    /* catalog ID */
2177                                          tdinfo->dobj.dumpId,   /* dump ID */
2178                                          tbinfo->dobj.name, /* Name */
2179                                          tbinfo->dobj.namespace->dobj.name, /* Namespace */
2180                                          NULL,          /* Tablespace */
2181                                          tbinfo->rolname,       /* Owner */
2182                                          false,         /* with oids */
2183                                          "MATERIALIZED VIEW DATA",      /* Desc */
2184                                          SECTION_POST_DATA, /* Section */
2185                                          q->data,       /* Create */
2186                                          "",            /* Del */
2187                                          NULL,          /* Copy */
2188                                          tdinfo->dobj.dependencies, /* Deps */
2189                                          tdinfo->dobj.nDeps,    /* # Deps */
2190                                          NULL,          /* Dumper */
2191                                          NULL);         /* Dumper Arg */
2192
2193         destroyPQExpBuffer(q);
2194 }
2195
2196 /*
2197  * getTableData -
2198  *        set up dumpable objects representing the contents of tables
2199  */
2200 static void
2201 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind)
2202 {
2203         int                     i;
2204
2205         for (i = 0; i < numTables; i++)
2206         {
2207                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2208                         (!relkind || tblinfo[i].relkind == relkind))
2209                         makeTableDataInfo(dopt, &(tblinfo[i]), oids);
2210         }
2211 }
2212
2213 /*
2214  * Make a dumpable object for the data of this specific table
2215  *
2216  * Note: we make a TableDataInfo if and only if we are going to dump the
2217  * table data; the "dump" flag in such objects isn't used.
2218  */
2219 static void
2220 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
2221 {
2222         TableDataInfo *tdinfo;
2223
2224         /*
2225          * Nothing to do if we already decided to dump the table.  This will
2226          * happen for "config" tables.
2227          */
2228         if (tbinfo->dataObj != NULL)
2229                 return;
2230
2231         /* Skip VIEWs (no data to dump) */
2232         if (tbinfo->relkind == RELKIND_VIEW)
2233                 return;
2234         /* Skip FOREIGN TABLEs (no data to dump) */
2235         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2236                 return;
2237         /* Skip partitioned tables (data in partitions) */
2238         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2239                 return;
2240
2241         /* Don't dump data in unlogged tables, if so requested */
2242         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2243                 dopt->no_unlogged_table_data)
2244                 return;
2245
2246         /* Check that the data is not explicitly excluded */
2247         if (simple_oid_list_member(&tabledata_exclude_oids,
2248                                                            tbinfo->dobj.catId.oid))
2249                 return;
2250
2251         /* OK, let's dump it */
2252         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2253
2254         if (tbinfo->relkind == RELKIND_MATVIEW)
2255                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2256         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2257                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2258         else
2259                 tdinfo->dobj.objType = DO_TABLE_DATA;
2260
2261         /*
2262          * Note: use tableoid 0 so that this object won't be mistaken for
2263          * something that pg_depend entries apply to.
2264          */
2265         tdinfo->dobj.catId.tableoid = 0;
2266         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2267         AssignDumpId(&tdinfo->dobj);
2268         tdinfo->dobj.name = tbinfo->dobj.name;
2269         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2270         tdinfo->tdtable = tbinfo;
2271         tdinfo->oids = oids;
2272         tdinfo->filtercond = NULL;      /* might get set later */
2273         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2274
2275         tbinfo->dataObj = tdinfo;
2276 }
2277
2278 /*
2279  * The refresh for a materialized view must be dependent on the refresh for
2280  * any materialized view that this one is dependent on.
2281  *
2282  * This must be called after all the objects are created, but before they are
2283  * sorted.
2284  */
2285 static void
2286 buildMatViewRefreshDependencies(Archive *fout)
2287 {
2288         PQExpBuffer query;
2289         PGresult   *res;
2290         int                     ntups,
2291                                 i;
2292         int                     i_classid,
2293                                 i_objid,
2294                                 i_refobjid;
2295
2296         /* No Mat Views before 9.3. */
2297         if (fout->remoteVersion < 90300)
2298                 return;
2299
2300         query = createPQExpBuffer();
2301
2302         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2303                                                  "( "
2304                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2305                                                  "FROM pg_depend d1 "
2306                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2307                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2308                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2309                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2310                                                  "AND d2.objid = r1.oid "
2311                                                  "AND d2.refobjid <> d1.objid "
2312                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2313                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2314                                                  CppAsString2(RELKIND_VIEW) ") "
2315                                                  "WHERE d1.classid = 'pg_class'::regclass "
2316                                                  "UNION "
2317                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2318                                                  "FROM w "
2319                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2320                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2321                                                  "AND d3.objid = r3.oid "
2322                                                  "AND d3.refobjid <> w.refobjid "
2323                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2324                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2325                                                  CppAsString2(RELKIND_VIEW) ") "
2326                                                  ") "
2327                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2328                                                  "FROM w "
2329                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2330
2331         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2332
2333         ntups = PQntuples(res);
2334
2335         i_classid = PQfnumber(res, "classid");
2336         i_objid = PQfnumber(res, "objid");
2337         i_refobjid = PQfnumber(res, "refobjid");
2338
2339         for (i = 0; i < ntups; i++)
2340         {
2341                 CatalogId       objId;
2342                 CatalogId       refobjId;
2343                 DumpableObject *dobj;
2344                 DumpableObject *refdobj;
2345                 TableInfo  *tbinfo;
2346                 TableInfo  *reftbinfo;
2347
2348                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2349                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2350                 refobjId.tableoid = objId.tableoid;
2351                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2352
2353                 dobj = findObjectByCatalogId(objId);
2354                 if (dobj == NULL)
2355                         continue;
2356
2357                 Assert(dobj->objType == DO_TABLE);
2358                 tbinfo = (TableInfo *) dobj;
2359                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2360                 dobj = (DumpableObject *) tbinfo->dataObj;
2361                 if (dobj == NULL)
2362                         continue;
2363                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2364
2365                 refdobj = findObjectByCatalogId(refobjId);
2366                 if (refdobj == NULL)
2367                         continue;
2368
2369                 Assert(refdobj->objType == DO_TABLE);
2370                 reftbinfo = (TableInfo *) refdobj;
2371                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2372                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2373                 if (refdobj == NULL)
2374                         continue;
2375                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2376
2377                 addObjectDependency(dobj, refdobj->dumpId);
2378
2379                 if (!reftbinfo->relispopulated)
2380                         tbinfo->relispopulated = false;
2381         }
2382
2383         PQclear(res);
2384
2385         destroyPQExpBuffer(query);
2386 }
2387
2388 /*
2389  * getTableDataFKConstraints -
2390  *        add dump-order dependencies reflecting foreign key constraints
2391  *
2392  * This code is executed only in a data-only dump --- in schema+data dumps
2393  * we handle foreign key issues by not creating the FK constraints until
2394  * after the data is loaded.  In a data-only dump, however, we want to
2395  * order the table data objects in such a way that a table's referenced
2396  * tables are restored first.  (In the presence of circular references or
2397  * self-references this may be impossible; we'll detect and complain about
2398  * that during the dependency sorting step.)
2399  */
2400 static void
2401 getTableDataFKConstraints(void)
2402 {
2403         DumpableObject **dobjs;
2404         int                     numObjs;
2405         int                     i;
2406
2407         /* Search through all the dumpable objects for FK constraints */
2408         getDumpableObjects(&dobjs, &numObjs);
2409         for (i = 0; i < numObjs; i++)
2410         {
2411                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2412                 {
2413                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2414                         TableInfo  *ftable;
2415
2416                         /* Not interesting unless both tables are to be dumped */
2417                         if (cinfo->contable == NULL ||
2418                                 cinfo->contable->dataObj == NULL)
2419                                 continue;
2420                         ftable = findTableByOid(cinfo->confrelid);
2421                         if (ftable == NULL ||
2422                                 ftable->dataObj == NULL)
2423                                 continue;
2424
2425                         /*
2426                          * Okay, make referencing table's TABLE_DATA object depend on the
2427                          * referenced table's TABLE_DATA object.
2428                          */
2429                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2430                                                                 ftable->dataObj->dobj.dumpId);
2431                 }
2432         }
2433         free(dobjs);
2434 }
2435
2436
2437 /*
2438  * guessConstraintInheritance:
2439  *      In pre-8.4 databases, we can't tell for certain which constraints
2440  *      are inherited.  We assume a CHECK constraint is inherited if its name
2441  *      matches the name of any constraint in the parent.  Originally this code
2442  *      tried to compare the expression texts, but that can fail for various
2443  *      reasons --- for example, if the parent and child tables are in different
2444  *      schemas, reverse-listing of function calls may produce different text
2445  *      (schema-qualified or not) depending on search path.
2446  *
2447  *      In 8.4 and up we can rely on the conislocal field to decide which
2448  *      constraints must be dumped; much safer.
2449  *
2450  *      This function assumes all conislocal flags were initialized to true.
2451  *      It clears the flag on anything that seems to be inherited.
2452  */
2453 static void
2454 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2455 {
2456         int                     i,
2457                                 j,
2458                                 k;
2459
2460         for (i = 0; i < numTables; i++)
2461         {
2462                 TableInfo  *tbinfo = &(tblinfo[i]);
2463                 int                     numParents;
2464                 TableInfo **parents;
2465                 TableInfo  *parent;
2466
2467                 /* Sequences and views never have parents */
2468                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2469                         tbinfo->relkind == RELKIND_VIEW)
2470                         continue;
2471
2472                 /* Don't bother computing anything for non-target tables, either */
2473                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2474                         continue;
2475
2476                 numParents = tbinfo->numParents;
2477                 parents = tbinfo->parents;
2478
2479                 if (numParents == 0)
2480                         continue;                       /* nothing to see here, move along */
2481
2482                 /* scan for inherited CHECK constraints */
2483                 for (j = 0; j < tbinfo->ncheck; j++)
2484                 {
2485                         ConstraintInfo *constr;
2486
2487                         constr = &(tbinfo->checkexprs[j]);
2488
2489                         for (k = 0; k < numParents; k++)
2490                         {
2491                                 int                     l;
2492
2493                                 parent = parents[k];
2494                                 for (l = 0; l < parent->ncheck; l++)
2495                                 {
2496                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2497
2498                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2499                                         {
2500                                                 constr->conislocal = false;
2501                                                 break;
2502                                         }
2503                                 }
2504                                 if (!constr->conislocal)
2505                                         break;
2506                         }
2507                 }
2508         }
2509 }
2510
2511
2512 /*
2513  * dumpDatabase:
2514  *      dump the database definition
2515  */
2516 static void
2517 dumpDatabase(Archive *fout)
2518 {
2519         DumpOptions *dopt = fout->dopt;
2520         PQExpBuffer dbQry = createPQExpBuffer();
2521         PQExpBuffer delQry = createPQExpBuffer();
2522         PQExpBuffer creaQry = createPQExpBuffer();
2523         PQExpBuffer labelq = createPQExpBuffer();
2524         PGconn     *conn = GetConnection(fout);
2525         PGresult   *res;
2526         int                     i_tableoid,
2527                                 i_oid,
2528                                 i_dba,
2529                                 i_encoding,
2530                                 i_collate,
2531                                 i_ctype,
2532                                 i_frozenxid,
2533                                 i_minmxid,
2534                                 i_datacl,
2535                                 i_rdatacl,
2536                                 i_datistemplate,
2537                                 i_datconnlimit,
2538                                 i_tablespace;
2539         CatalogId       dbCatId;
2540         DumpId          dbDumpId;
2541         const char *datname,
2542                            *dba,
2543                            *encoding,
2544                            *collate,
2545                            *ctype,
2546                            *datacl,
2547                            *rdatacl,
2548                            *datistemplate,
2549                            *datconnlimit,
2550                            *tablespace;
2551         uint32          frozenxid,
2552                                 minmxid;
2553         char       *qdatname;
2554
2555         datname = PQdb(conn);
2556         qdatname = pg_strdup(fmtId(datname));
2557
2558         if (g_verbose)
2559                 write_msg(NULL, "saving database definition\n");
2560
2561         /* Fetch the database-level properties for this database */
2562         if (fout->remoteVersion >= 90600)
2563         {
2564                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2565                                                   "(%s datdba) AS dba, "
2566                                                   "pg_encoding_to_char(encoding) AS encoding, "
2567                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2568                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2569                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2570                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2571                                                   " AS datacl, "
2572                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2573                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2574                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2575                                                   " AS rdatacl, "
2576                                                   "datistemplate, datconnlimit, "
2577                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2578                                                   "shobj_description(oid, 'pg_database') AS description "
2579
2580                                                   "FROM pg_database "
2581                                                   "WHERE datname = ",
2582                                                   username_subquery);
2583                 appendStringLiteralAH(dbQry, datname, fout);
2584         }
2585         else if (fout->remoteVersion >= 90300)
2586         {
2587                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2588                                                   "(%s datdba) AS dba, "
2589                                                   "pg_encoding_to_char(encoding) AS encoding, "
2590                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2591                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2592                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2593                                                   "shobj_description(oid, 'pg_database') AS description "
2594
2595                                                   "FROM pg_database "
2596                                                   "WHERE datname = ",
2597                                                   username_subquery);
2598                 appendStringLiteralAH(dbQry, datname, fout);
2599         }
2600         else if (fout->remoteVersion >= 80400)
2601         {
2602                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2603                                                   "(%s datdba) AS dba, "
2604                                                   "pg_encoding_to_char(encoding) AS encoding, "
2605                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2606                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2607                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2608                                                   "shobj_description(oid, 'pg_database') AS description "
2609
2610                                                   "FROM pg_database "
2611                                                   "WHERE datname = ",
2612                                                   username_subquery);
2613                 appendStringLiteralAH(dbQry, datname, fout);
2614         }
2615         else if (fout->remoteVersion >= 80200)
2616         {
2617                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2618                                                   "(%s datdba) AS dba, "
2619                                                   "pg_encoding_to_char(encoding) AS encoding, "
2620                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2621                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2622                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2623                                                   "shobj_description(oid, 'pg_database') AS description "
2624
2625                                                   "FROM pg_database "
2626                                                   "WHERE datname = ",
2627                                                   username_subquery);
2628                 appendStringLiteralAH(dbQry, datname, fout);
2629         }
2630         else
2631         {
2632                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2633                                                   "(%s datdba) AS dba, "
2634                                                   "pg_encoding_to_char(encoding) AS encoding, "
2635                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2636                                                   "datacl, '' as rdatacl, datistemplate, "
2637                                                   "-1 as datconnlimit, "
2638                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2639                                                   "FROM pg_database "
2640                                                   "WHERE datname = ",
2641                                                   username_subquery);
2642                 appendStringLiteralAH(dbQry, datname, fout);
2643         }
2644
2645         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2646
2647         i_tableoid = PQfnumber(res, "tableoid");
2648         i_oid = PQfnumber(res, "oid");
2649         i_dba = PQfnumber(res, "dba");
2650         i_encoding = PQfnumber(res, "encoding");
2651         i_collate = PQfnumber(res, "datcollate");
2652         i_ctype = PQfnumber(res, "datctype");
2653         i_frozenxid = PQfnumber(res, "datfrozenxid");
2654         i_minmxid = PQfnumber(res, "datminmxid");
2655         i_datacl = PQfnumber(res, "datacl");
2656         i_rdatacl = PQfnumber(res, "rdatacl");
2657         i_datistemplate = PQfnumber(res, "datistemplate");
2658         i_datconnlimit = PQfnumber(res, "datconnlimit");
2659         i_tablespace = PQfnumber(res, "tablespace");
2660
2661         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2662         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2663         dba = PQgetvalue(res, 0, i_dba);
2664         encoding = PQgetvalue(res, 0, i_encoding);
2665         collate = PQgetvalue(res, 0, i_collate);
2666         ctype = PQgetvalue(res, 0, i_ctype);
2667         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2668         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2669         datacl = PQgetvalue(res, 0, i_datacl);
2670         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2671         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2672         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2673         tablespace = PQgetvalue(res, 0, i_tablespace);
2674
2675         /*
2676          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2677          * and tablespace since those can't be altered later.  Other DB properties
2678          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2679          * after reconnecting to the target DB.
2680          */
2681         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2682                                           qdatname);
2683         if (strlen(encoding) > 0)
2684         {
2685                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2686                 appendStringLiteralAH(creaQry, encoding, fout);
2687         }
2688         if (strlen(collate) > 0)
2689         {
2690                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2691                 appendStringLiteralAH(creaQry, collate, fout);
2692         }
2693         if (strlen(ctype) > 0)
2694         {
2695                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2696                 appendStringLiteralAH(creaQry, ctype, fout);
2697         }
2698
2699         /*
2700          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2701          * thing; the decision whether to specify a tablespace should be left till
2702          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2703          * label the DATABASE entry with the tablespace and let the normal
2704          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2705          * attention to default_tablespace, so that won't work.
2706          */
2707         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2708                 !dopt->outputNoTablespaces)
2709                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2710                                                   fmtId(tablespace));
2711         appendPQExpBufferStr(creaQry, ";\n");
2712
2713         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2714                                           qdatname);
2715
2716         dbDumpId = createDumpId();
2717
2718         ArchiveEntry(fout,
2719                                  dbCatId,               /* catalog ID */
2720                                  dbDumpId,              /* dump ID */
2721                                  datname,               /* Name */
2722                                  NULL,                  /* Namespace */
2723                                  NULL,                  /* Tablespace */
2724                                  dba,                   /* Owner */
2725                                  false,                 /* with oids */
2726                                  "DATABASE",    /* Desc */
2727                                  SECTION_PRE_DATA,      /* Section */
2728                                  creaQry->data, /* Create */
2729                                  delQry->data,  /* Del */
2730                                  NULL,                  /* Copy */
2731                                  NULL,                  /* Deps */
2732                                  0,                             /* # Deps */
2733                                  NULL,                  /* Dumper */
2734                                  NULL);                 /* Dumper Arg */
2735
2736         /* Compute correct tag for archive entry */
2737         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2738
2739         /* Dump DB comment if any */
2740         if (fout->remoteVersion >= 80200)
2741         {
2742                 /*
2743                  * 8.2 and up keep comments on shared objects in a shared table, so we
2744                  * cannot use the dumpComment() code used for other database objects.
2745                  * Be careful that the ArchiveEntry parameters match that function.
2746                  */
2747                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2748
2749                 if (comment && *comment && !dopt->no_comments)
2750                 {
2751                         resetPQExpBuffer(dbQry);
2752
2753                         /*
2754                          * Generates warning when loaded into a differently-named
2755                          * database.
2756                          */
2757                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2758                         appendStringLiteralAH(dbQry, comment, fout);
2759                         appendPQExpBufferStr(dbQry, ";\n");
2760
2761                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2762                                                  labelq->data, NULL, NULL, dba,
2763                                                  false, "COMMENT", SECTION_NONE,
2764                                                  dbQry->data, "", NULL,
2765                                                  &(dbDumpId), 1,
2766                                                  NULL, NULL);
2767                 }
2768         }
2769         else
2770         {
2771                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2772                                         dbCatId, 0, dbDumpId);
2773         }
2774
2775         /* Dump DB security label, if enabled */
2776         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2777         {
2778                 PGresult   *shres;
2779                 PQExpBuffer seclabelQry;
2780
2781                 seclabelQry = createPQExpBuffer();
2782
2783                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2784                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2785                 resetPQExpBuffer(seclabelQry);
2786                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2787                 if (seclabelQry->len > 0)
2788                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2789                                                  labelq->data, NULL, NULL, dba,
2790                                                  false, "SECURITY LABEL", SECTION_NONE,
2791                                                  seclabelQry->data, "", NULL,
2792                                                  &(dbDumpId), 1,
2793                                                  NULL, NULL);
2794                 destroyPQExpBuffer(seclabelQry);
2795                 PQclear(shres);
2796         }
2797
2798         /*
2799          * Dump ACL if any.  Note that we do not support initial privileges
2800          * (pg_init_privs) on databases.
2801          */
2802         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2803                         qdatname, NULL, NULL,
2804                         dba, datacl, rdatacl, "", "");
2805
2806         /*
2807          * Now construct a DATABASE PROPERTIES archive entry to restore any
2808          * non-default database-level properties.  (The reason this must be
2809          * separate is that we cannot put any additional commands into the TOC
2810          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2811          * in an implicit transaction block, and the backend won't allow CREATE
2812          * DATABASE in that context.)
2813          */
2814         resetPQExpBuffer(creaQry);
2815         resetPQExpBuffer(delQry);
2816
2817         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2818                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2819                                                   qdatname, datconnlimit);
2820
2821         if (strcmp(datistemplate, "t") == 0)
2822         {
2823                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2824                                                   qdatname);
2825
2826                 /*
2827                  * The backend won't accept DROP DATABASE on a template database.  We
2828                  * can deal with that by removing the template marking before the DROP
2829                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2830                  * since no such command is currently supported, fake it with a direct
2831                  * UPDATE on pg_database.
2832                  */
2833                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2834                                                          "SET datistemplate = false WHERE datname = ");
2835                 appendStringLiteralAH(delQry, datname, fout);
2836                 appendPQExpBufferStr(delQry, ";\n");
2837         }
2838
2839         /* Add database-specific SET options */
2840         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2841
2842         /*
2843          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2844          * entry, too, for lack of a better place.
2845          */
2846         if (dopt->binary_upgrade)
2847         {
2848                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2849                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2850                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2851                                                   "WHERE datname = ",
2852                                                   frozenxid, minmxid);
2853                 appendStringLiteralAH(creaQry, datname, fout);
2854                 appendPQExpBufferStr(creaQry, ";\n");
2855         }
2856
2857         if (creaQry->len > 0)
2858                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2859                                          datname, NULL, NULL, dba,
2860                                          false, "DATABASE PROPERTIES", SECTION_PRE_DATA,
2861                                          creaQry->data, delQry->data, NULL,
2862                                          &(dbDumpId), 1,
2863                                          NULL, NULL);
2864
2865         /*
2866          * pg_largeobject and pg_largeobject_metadata come from the old system
2867          * intact, so set their relfrozenxids and relminmxids.
2868          */
2869         if (dopt->binary_upgrade)
2870         {
2871                 PGresult   *lo_res;
2872                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2873                 PQExpBuffer loOutQry = createPQExpBuffer();
2874                 int                     i_relfrozenxid,
2875                                         i_relminmxid;
2876
2877                 /*
2878                  * pg_largeobject
2879                  */
2880                 if (fout->remoteVersion >= 90300)
2881                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2882                                                           "FROM pg_catalog.pg_class\n"
2883                                                           "WHERE oid = %u;\n",
2884                                                           LargeObjectRelationId);
2885                 else
2886                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2887                                                           "FROM pg_catalog.pg_class\n"
2888                                                           "WHERE oid = %u;\n",
2889                                                           LargeObjectRelationId);
2890
2891                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2892
2893                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2894                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2895
2896                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2897                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2898                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2899                                                   "WHERE oid = %u;\n",
2900                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2901                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2902                                                   LargeObjectRelationId);
2903                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2904                                          "pg_largeobject", NULL, NULL, "",
2905                                          false, "pg_largeobject", SECTION_PRE_DATA,
2906                                          loOutQry->data, "", NULL,
2907                                          NULL, 0,
2908                                          NULL, NULL);
2909
2910                 PQclear(lo_res);
2911
2912                 /*
2913                  * pg_largeobject_metadata
2914                  */
2915                 if (fout->remoteVersion >= 90000)
2916                 {
2917                         resetPQExpBuffer(loFrozenQry);
2918                         resetPQExpBuffer(loOutQry);
2919
2920                         if (fout->remoteVersion >= 90300)
2921                                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2922                                                                   "FROM pg_catalog.pg_class\n"
2923                                                                   "WHERE oid = %u;\n",
2924                                                                   LargeObjectMetadataRelationId);
2925                         else
2926                                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2927                                                                   "FROM pg_catalog.pg_class\n"
2928                                                                   "WHERE oid = %u;\n",
2929                                                                   LargeObjectMetadataRelationId);
2930
2931                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2932
2933                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2934                         i_relminmxid = PQfnumber(lo_res, "relminmxid");
2935
2936                         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2937                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2938                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2939                                                           "WHERE oid = %u;\n",
2940                                                           atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2941                                                           atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2942                                                           LargeObjectMetadataRelationId);
2943                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2944                                                  "pg_largeobject_metadata", NULL, NULL, "",
2945                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2946                                                  loOutQry->data, "", NULL,
2947                                                  NULL, 0,
2948                                                  NULL, NULL);
2949
2950                         PQclear(lo_res);
2951                 }
2952
2953                 destroyPQExpBuffer(loFrozenQry);
2954                 destroyPQExpBuffer(loOutQry);
2955         }
2956
2957         PQclear(res);
2958
2959         free(qdatname);
2960         destroyPQExpBuffer(dbQry);
2961         destroyPQExpBuffer(delQry);
2962         destroyPQExpBuffer(creaQry);
2963         destroyPQExpBuffer(labelq);
2964 }
2965
2966 /*
2967  * Collect any database-specific or role-and-database-specific SET options
2968  * for this database, and append them to outbuf.
2969  */
2970 static void
2971 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
2972                                    const char *dbname, Oid dboid)
2973 {
2974         PGconn     *conn = GetConnection(AH);
2975         PQExpBuffer buf = createPQExpBuffer();
2976         PGresult   *res;
2977         int                     count = 1;
2978
2979         /*
2980          * First collect database-specific options.  Pre-8.4 server versions lack
2981          * unnest(), so we do this the hard way by querying once per subscript.
2982          */
2983         for (;;)
2984         {
2985                 if (AH->remoteVersion >= 90000)
2986                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
2987                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
2988                                                           count, dboid);
2989                 else
2990                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
2991
2992                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
2993
2994                 if (PQntuples(res) == 1 &&
2995                         !PQgetisnull(res, 0, 0))
2996                 {
2997                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
2998                                                                    "DATABASE", dbname, NULL, NULL,
2999                                                                    outbuf);
3000                         PQclear(res);
3001                         count++;
3002                 }
3003                 else
3004                 {
3005                         PQclear(res);
3006                         break;
3007                 }
3008         }
3009
3010         /* Now look for role-and-database-specific options */
3011         if (AH->remoteVersion >= 90000)
3012         {
3013                 /* Here we can assume we have unnest() */
3014                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3015                                                   "FROM pg_db_role_setting s, pg_roles r "
3016                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3017                                                   dboid);
3018
3019                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3020
3021                 if (PQntuples(res) > 0)
3022                 {
3023                         int                     i;
3024
3025                         for (i = 0; i < PQntuples(res); i++)
3026                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3027                                                                            "ROLE", PQgetvalue(res, i, 0),
3028                                                                            "DATABASE", dbname,
3029                                                                            outbuf);
3030                 }
3031
3032                 PQclear(res);
3033         }
3034
3035         destroyPQExpBuffer(buf);
3036 }
3037
3038 /*
3039  * dumpEncoding: put the correct encoding into the archive
3040  */
3041 static void
3042 dumpEncoding(Archive *AH)
3043 {
3044         const char *encname = pg_encoding_to_char(AH->encoding);
3045         PQExpBuffer qry = createPQExpBuffer();
3046
3047         if (g_verbose)
3048                 write_msg(NULL, "saving encoding = %s\n", encname);
3049
3050         appendPQExpBufferStr(qry, "SET client_encoding = ");
3051         appendStringLiteralAH(qry, encname, AH);
3052         appendPQExpBufferStr(qry, ";\n");
3053
3054         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3055                                  "ENCODING", NULL, NULL, "",
3056                                  false, "ENCODING", SECTION_PRE_DATA,
3057                                  qry->data, "", NULL,
3058                                  NULL, 0,
3059                                  NULL, NULL);
3060
3061         destroyPQExpBuffer(qry);
3062 }
3063
3064
3065 /*
3066  * dumpStdStrings: put the correct escape string behavior into the archive
3067  */
3068 static void
3069 dumpStdStrings(Archive *AH)
3070 {
3071         const char *stdstrings = AH->std_strings ? "on" : "off";
3072         PQExpBuffer qry = createPQExpBuffer();
3073
3074         if (g_verbose)
3075                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3076                                   stdstrings);
3077
3078         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3079                                           stdstrings);
3080
3081         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3082                                  "STDSTRINGS", NULL, NULL, "",
3083                                  false, "STDSTRINGS", SECTION_PRE_DATA,
3084                                  qry->data, "", NULL,
3085                                  NULL, 0,
3086                                  NULL, NULL);
3087
3088         destroyPQExpBuffer(qry);
3089 }
3090
3091 /*
3092  * dumpSearchPath: record the active search_path in the archive
3093  */
3094 static void
3095 dumpSearchPath(Archive *AH)
3096 {
3097         PQExpBuffer qry = createPQExpBuffer();
3098         PQExpBuffer path = createPQExpBuffer();
3099         PGresult   *res;
3100         char      **schemanames = NULL;
3101         int                     nschemanames = 0;
3102         int                     i;
3103
3104         /*
3105          * We use the result of current_schemas(), not the search_path GUC,
3106          * because that might contain wildcards such as "$user", which won't
3107          * necessarily have the same value during restore.  Also, this way avoids
3108          * listing schemas that may appear in search_path but not actually exist,
3109          * which seems like a prudent exclusion.
3110          */
3111         res = ExecuteSqlQueryForSingleRow(AH,
3112                                                                           "SELECT pg_catalog.current_schemas(false)");
3113
3114         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3115                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3116
3117         /*
3118          * We use set_config(), not a simple "SET search_path" command, because
3119          * the latter has less-clean behavior if the search path is empty.  While
3120          * that's likely to get fixed at some point, it seems like a good idea to
3121          * be as backwards-compatible as possible in what we put into archives.
3122          */
3123         for (i = 0; i < nschemanames; i++)
3124         {
3125                 if (i > 0)
3126                         appendPQExpBufferStr(path, ", ");
3127                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3128         }
3129
3130         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3131         appendStringLiteralAH(qry, path->data, AH);
3132         appendPQExpBufferStr(qry, ", false);\n");
3133
3134         if (g_verbose)
3135                 write_msg(NULL, "saving search_path = %s\n", path->data);
3136
3137         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3138                                  "SEARCHPATH", NULL, NULL, "",
3139                                  false, "SEARCHPATH", SECTION_PRE_DATA,
3140                                  qry->data, "", NULL,
3141                                  NULL, 0,
3142                                  NULL, NULL);
3143
3144         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3145         AH->searchpath = pg_strdup(qry->data);
3146
3147         if (schemanames)
3148                 free(schemanames);
3149         PQclear(res);
3150         destroyPQExpBuffer(qry);
3151         destroyPQExpBuffer(path);
3152 }
3153
3154
3155 /*
3156  * getBlobs:
3157  *      Collect schema-level data about large objects
3158  */
3159 static void
3160 getBlobs(Archive *fout)
3161 {
3162         DumpOptions *dopt = fout->dopt;
3163         PQExpBuffer blobQry = createPQExpBuffer();
3164         BlobInfo   *binfo;
3165         DumpableObject *bdata;
3166         PGresult   *res;
3167         int                     ntups;
3168         int                     i;
3169         int                     i_oid;
3170         int                     i_lomowner;
3171         int                     i_lomacl;
3172         int                     i_rlomacl;
3173         int                     i_initlomacl;
3174         int                     i_initrlomacl;
3175
3176         /* Verbose message */
3177         if (g_verbose)
3178                 write_msg(NULL, "reading large objects\n");
3179
3180         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3181         if (fout->remoteVersion >= 90600)
3182         {
3183                 PQExpBuffer acl_subquery = createPQExpBuffer();
3184                 PQExpBuffer racl_subquery = createPQExpBuffer();
3185                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3186                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3187
3188                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3189                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3190                                                 dopt->binary_upgrade);
3191
3192                 appendPQExpBuffer(blobQry,
3193                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3194                                                   "%s AS lomacl, "
3195                                                   "%s AS rlomacl, "
3196                                                   "%s AS initlomacl, "
3197                                                   "%s AS initrlomacl "
3198                                                   "FROM pg_largeobject_metadata l "
3199                                                   "LEFT JOIN pg_init_privs pip ON "
3200                                                   "(l.oid = pip.objoid "
3201                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3202                                                   "AND pip.objsubid = 0) ",
3203                                                   username_subquery,
3204                                                   acl_subquery->data,
3205                                                   racl_subquery->data,
3206                                                   init_acl_subquery->data,
3207                                                   init_racl_subquery->data);
3208
3209                 destroyPQExpBuffer(acl_subquery);
3210                 destroyPQExpBuffer(racl_subquery);
3211                 destroyPQExpBuffer(init_acl_subquery);
3212                 destroyPQExpBuffer(init_racl_subquery);
3213         }
3214         else if (fout->remoteVersion >= 90000)
3215                 appendPQExpBuffer(blobQry,
3216                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3217                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3218                                                   "NULL AS initrlomacl "
3219                                                   " FROM pg_largeobject_metadata",
3220                                                   username_subquery);
3221         else
3222                 appendPQExpBufferStr(blobQry,
3223                                                          "SELECT DISTINCT loid AS oid, "
3224                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3225                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3226                                                          "NULL::oid AS initrlomacl "
3227                                                          " FROM pg_largeobject");
3228
3229         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3230
3231         i_oid = PQfnumber(res, "oid");
3232         i_lomowner = PQfnumber(res, "rolname");
3233         i_lomacl = PQfnumber(res, "lomacl");
3234         i_rlomacl = PQfnumber(res, "rlomacl");
3235         i_initlomacl = PQfnumber(res, "initlomacl");
3236         i_initrlomacl = PQfnumber(res, "initrlomacl");
3237
3238         ntups = PQntuples(res);
3239
3240         /*
3241          * Each large object has its own BLOB archive entry.
3242          */
3243         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3244
3245         for (i = 0; i < ntups; i++)
3246         {
3247                 binfo[i].dobj.objType = DO_BLOB;
3248                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3249                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3250                 AssignDumpId(&binfo[i].dobj);
3251
3252                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3253                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3254                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3255                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3256                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3257                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3258
3259                 if (PQgetisnull(res, i, i_lomacl) &&
3260                         PQgetisnull(res, i, i_rlomacl) &&
3261                         PQgetisnull(res, i, i_initlomacl) &&
3262                         PQgetisnull(res, i, i_initrlomacl))
3263                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3264
3265                 /*
3266                  * In binary-upgrade mode for blobs, we do *not* dump out the data or
3267                  * the ACLs, should any exist.  The data and ACL (if any) will be
3268                  * copied by pg_upgrade, which simply copies the pg_largeobject and
3269                  * pg_largeobject_metadata tables.
3270                  *
3271                  * We *do* dump out the definition of the blob because we need that to
3272                  * make the restoration of the comments, and anything else, work since
3273                  * pg_upgrade copies the files behind pg_largeobject and
3274                  * pg_largeobject_metadata after the dump is restored.
3275                  */
3276                 if (dopt->binary_upgrade)
3277                         binfo[i].dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL);
3278         }
3279
3280         /*
3281          * If we have any large objects, a "BLOBS" archive entry is needed. This
3282          * is just a placeholder for sorting; it carries no data now.
3283          */
3284         if (ntups > 0)
3285         {
3286                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3287                 bdata->objType = DO_BLOB_DATA;
3288                 bdata->catId = nilCatalogId;
3289                 AssignDumpId(bdata);
3290                 bdata->name = pg_strdup("BLOBS");
3291         }
3292
3293         PQclear(res);
3294         destroyPQExpBuffer(blobQry);
3295 }
3296
3297 /*
3298  * dumpBlob
3299  *
3300  * dump the definition (metadata) of the given large object
3301  */
3302 static void
3303 dumpBlob(Archive *fout, BlobInfo *binfo)
3304 {
3305         PQExpBuffer cquery = createPQExpBuffer();
3306         PQExpBuffer dquery = createPQExpBuffer();
3307
3308         appendPQExpBuffer(cquery,
3309                                           "SELECT pg_catalog.lo_create('%s');\n",
3310                                           binfo->dobj.name);
3311
3312         appendPQExpBuffer(dquery,
3313                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3314                                           binfo->dobj.name);
3315
3316         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3317                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3318                                          binfo->dobj.name,
3319                                          NULL, NULL,
3320                                          binfo->rolname, false,
3321                                          "BLOB", SECTION_PRE_DATA,
3322                                          cquery->data, dquery->data, NULL,
3323                                          NULL, 0,
3324                                          NULL, NULL);
3325
3326         /* Dump comment if any */
3327         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3328                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3329                                         NULL, binfo->rolname,
3330                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3331
3332         /* Dump security label if any */
3333         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3334                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3335                                          NULL, binfo->rolname,
3336                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3337
3338         /* Dump ACL if any */
3339         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3340                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3341                                 binfo->dobj.name, NULL,
3342                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3343                                 binfo->initblobacl, binfo->initrblobacl);
3344
3345         destroyPQExpBuffer(cquery);
3346         destroyPQExpBuffer(dquery);
3347 }
3348
3349 /*
3350  * dumpBlobs:
3351  *      dump the data contents of all large objects
3352  */
3353 static int
3354 dumpBlobs(Archive *fout, void *arg)
3355 {
3356         const char *blobQry;
3357         const char *blobFetchQry;
3358         PGconn     *conn = GetConnection(fout);
3359         PGresult   *res;
3360         char            buf[LOBBUFSIZE];
3361         int                     ntups;
3362         int                     i;
3363         int                     cnt;
3364
3365         if (g_verbose)
3366                 write_msg(NULL, "saving large objects\n");
3367
3368         /*
3369          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3370          * the already-in-memory dumpable objects instead...
3371          */
3372         if (fout->remoteVersion >= 90000)
3373                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
3374         else
3375                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
3376
3377         ExecuteSqlStatement(fout, blobQry);
3378
3379         /* Command to fetch from cursor */
3380         blobFetchQry = "FETCH 1000 IN bloboid";
3381
3382         do
3383         {
3384                 /* Do a fetch */
3385                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3386
3387                 /* Process the tuples, if any */
3388                 ntups = PQntuples(res);
3389                 for (i = 0; i < ntups; i++)
3390                 {
3391                         Oid                     blobOid;
3392                         int                     loFd;
3393
3394                         blobOid = atooid(PQgetvalue(res, i, 0));
3395                         /* Open the BLOB */
3396                         loFd = lo_open(conn, blobOid, INV_READ);
3397                         if (loFd == -1)
3398                                 exit_horribly(NULL, "could not open large object %u: %s",
3399                                                           blobOid, PQerrorMessage(conn));
3400
3401                         StartBlob(fout, blobOid);
3402
3403                         /* Now read it in chunks, sending data to archive */
3404                         do
3405                         {
3406                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3407                                 if (cnt < 0)
3408                                         exit_horribly(NULL, "error reading large object %u: %s",
3409                                                                   blobOid, PQerrorMessage(conn));
3410
3411                                 WriteData(fout, buf, cnt);
3412                         } while (cnt > 0);
3413
3414                         lo_close(conn, loFd);
3415
3416                         EndBlob(fout, blobOid);
3417                 }
3418
3419                 PQclear(res);
3420         } while (ntups > 0);
3421
3422         return 1;
3423 }
3424
3425 /*
3426  * getPolicies
3427  *        get information about policies on a dumpable table.
3428  */
3429 void
3430 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3431 {
3432         PQExpBuffer query;
3433         PGresult   *res;
3434         PolicyInfo *polinfo;
3435         int                     i_oid;
3436         int                     i_tableoid;
3437         int                     i_polname;
3438         int                     i_polcmd;
3439         int                     i_polpermissive;
3440         int                     i_polroles;
3441         int                     i_polqual;
3442         int                     i_polwithcheck;
3443         int                     i,
3444                                 j,
3445                                 ntups;
3446
3447         if (fout->remoteVersion < 90500)
3448                 return;
3449
3450         query = createPQExpBuffer();
3451
3452         for (i = 0; i < numTables; i++)
3453         {
3454                 TableInfo  *tbinfo = &tblinfo[i];
3455
3456                 /* Ignore row security on tables not to be dumped */
3457                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3458                         continue;
3459
3460                 if (g_verbose)
3461                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3462                                           tbinfo->dobj.namespace->dobj.name,
3463                                           tbinfo->dobj.name);
3464
3465                 /*
3466                  * Get row security enabled information for the table. We represent
3467                  * RLS enabled on a table by creating PolicyInfo object with an empty
3468                  * policy.
3469                  */
3470                 if (tbinfo->rowsec)
3471                 {
3472                         /*
3473                          * Note: use tableoid 0 so that this object won't be mistaken for
3474                          * something that pg_depend entries apply to.
3475                          */
3476                         polinfo = pg_malloc(sizeof(PolicyInfo));
3477                         polinfo->dobj.objType = DO_POLICY;
3478                         polinfo->dobj.catId.tableoid = 0;
3479                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3480                         AssignDumpId(&polinfo->dobj);
3481                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3482                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3483                         polinfo->poltable = tbinfo;
3484                         polinfo->polname = NULL;
3485                         polinfo->polcmd = '\0';
3486                         polinfo->polpermissive = 0;
3487                         polinfo->polroles = NULL;
3488                         polinfo->polqual = NULL;
3489                         polinfo->polwithcheck = NULL;
3490                 }
3491
3492                 if (g_verbose)
3493                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3494                                           tbinfo->dobj.namespace->dobj.name,
3495                                           tbinfo->dobj.name);
3496
3497                 resetPQExpBuffer(query);
3498
3499                 /* Get the policies for the table. */
3500                 if (fout->remoteVersion >= 100000)
3501                         appendPQExpBuffer(query,
3502                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3503                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3504                                                           "   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, "
3505                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3506                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3507                                                           "FROM pg_catalog.pg_policy pol "
3508                                                           "WHERE polrelid = '%u'",
3509                                                           tbinfo->dobj.catId.oid);
3510                 else
3511                         appendPQExpBuffer(query,
3512                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3513                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3514                                                           "   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, "
3515                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3516                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3517                                                           "FROM pg_catalog.pg_policy pol "
3518                                                           "WHERE polrelid = '%u'",
3519                                                           tbinfo->dobj.catId.oid);
3520                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3521
3522                 ntups = PQntuples(res);
3523
3524                 if (ntups == 0)
3525                 {
3526                         /*
3527                          * No explicit policies to handle (only the default-deny policy,
3528                          * which is handled as part of the table definition).  Clean up
3529                          * and return.
3530                          */
3531                         PQclear(res);
3532                         continue;
3533                 }
3534
3535                 i_oid = PQfnumber(res, "oid");
3536                 i_tableoid = PQfnumber(res, "tableoid");
3537                 i_polname = PQfnumber(res, "polname");
3538                 i_polcmd = PQfnumber(res, "polcmd");
3539                 i_polpermissive = PQfnumber(res, "polpermissive");
3540                 i_polroles = PQfnumber(res, "polroles");
3541                 i_polqual = PQfnumber(res, "polqual");
3542                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3543
3544                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3545
3546                 for (j = 0; j < ntups; j++)
3547                 {
3548                         polinfo[j].dobj.objType = DO_POLICY;
3549                         polinfo[j].dobj.catId.tableoid =
3550                                 atooid(PQgetvalue(res, j, i_tableoid));
3551                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3552                         AssignDumpId(&polinfo[j].dobj);
3553                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3554                         polinfo[j].poltable = tbinfo;
3555                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3556                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3557
3558                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3559                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3560
3561                         if (PQgetisnull(res, j, i_polroles))
3562                                 polinfo[j].polroles = NULL;
3563                         else
3564                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3565
3566                         if (PQgetisnull(res, j, i_polqual))
3567                                 polinfo[j].polqual = NULL;
3568                         else
3569                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3570
3571                         if (PQgetisnull(res, j, i_polwithcheck))
3572                                 polinfo[j].polwithcheck = NULL;
3573                         else
3574                                 polinfo[j].polwithcheck
3575                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3576                 }
3577                 PQclear(res);
3578         }
3579         destroyPQExpBuffer(query);
3580 }
3581
3582 /*
3583  * dumpPolicy
3584  *        dump the definition of the given policy
3585  */
3586 static void
3587 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3588 {
3589         DumpOptions *dopt = fout->dopt;
3590         TableInfo  *tbinfo = polinfo->poltable;
3591         PQExpBuffer query;
3592         PQExpBuffer delqry;
3593         const char *cmd;
3594         char       *tag;
3595
3596         if (dopt->dataOnly)
3597                 return;
3598
3599         /*
3600          * If polname is NULL, then this record is just indicating that ROW LEVEL
3601          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3602          * ROW LEVEL SECURITY.
3603          */
3604         if (polinfo->polname == NULL)
3605         {
3606                 query = createPQExpBuffer();
3607
3608                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3609                                                   fmtQualifiedDumpable(polinfo));
3610
3611                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3612                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3613                                                  polinfo->dobj.name,
3614                                                  polinfo->dobj.namespace->dobj.name,
3615                                                  NULL,
3616                                                  tbinfo->rolname, false,
3617                                                  "ROW SECURITY", SECTION_POST_DATA,
3618                                                  query->data, "", NULL,
3619                                                  NULL, 0,
3620                                                  NULL, NULL);
3621
3622                 destroyPQExpBuffer(query);
3623                 return;
3624         }
3625
3626         if (polinfo->polcmd == '*')
3627                 cmd = "";
3628         else if (polinfo->polcmd == 'r')
3629                 cmd = " FOR SELECT";
3630         else if (polinfo->polcmd == 'a')
3631                 cmd = " FOR INSERT";
3632         else if (polinfo->polcmd == 'w')
3633                 cmd = " FOR UPDATE";
3634         else if (polinfo->polcmd == 'd')
3635                 cmd = " FOR DELETE";
3636         else
3637         {
3638                 write_msg(NULL, "unexpected policy command type: %c\n",
3639                                   polinfo->polcmd);
3640                 exit_nicely(1);
3641         }
3642
3643         query = createPQExpBuffer();
3644         delqry = createPQExpBuffer();
3645
3646         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3647
3648         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3649                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3650
3651         if (polinfo->polroles != NULL)
3652                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3653
3654         if (polinfo->polqual != NULL)
3655                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3656
3657         if (polinfo->polwithcheck != NULL)
3658                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3659
3660         appendPQExpBuffer(query, ";\n");
3661
3662         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3663         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3664
3665         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3666
3667         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3668                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3669                                          tag,
3670                                          polinfo->dobj.namespace->dobj.name,
3671                                          NULL,
3672                                          tbinfo->rolname, false,
3673                                          "POLICY", SECTION_POST_DATA,
3674                                          query->data, delqry->data, NULL,
3675                                          NULL, 0,
3676                                          NULL, NULL);
3677
3678         free(tag);
3679         destroyPQExpBuffer(query);
3680         destroyPQExpBuffer(delqry);
3681 }
3682
3683 /*
3684  * getPublications
3685  *        get information about publications
3686  */
3687 void
3688 getPublications(Archive *fout)
3689 {
3690         DumpOptions *dopt = fout->dopt;
3691         PQExpBuffer query;
3692         PGresult   *res;
3693         PublicationInfo *pubinfo;
3694         int                     i_tableoid;
3695         int                     i_oid;
3696         int                     i_pubname;
3697         int                     i_rolname;
3698         int                     i_puballtables;
3699         int                     i_pubinsert;
3700         int                     i_pubupdate;
3701         int                     i_pubdelete;
3702         int                     i,
3703                                 ntups;
3704
3705         if (dopt->no_publications || fout->remoteVersion < 100000)
3706                 return;
3707
3708         query = createPQExpBuffer();
3709
3710         resetPQExpBuffer(query);
3711
3712         /* Get the publications. */
3713         appendPQExpBuffer(query,
3714                                           "SELECT p.tableoid, p.oid, p.pubname, "
3715                                           "(%s p.pubowner) AS rolname, "
3716                                           "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete "
3717                                           "FROM pg_publication p",
3718                                           username_subquery);
3719
3720         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3721
3722         ntups = PQntuples(res);
3723
3724         i_tableoid = PQfnumber(res, "tableoid");
3725         i_oid = PQfnumber(res, "oid");
3726         i_pubname = PQfnumber(res, "pubname");
3727         i_rolname = PQfnumber(res, "rolname");
3728         i_puballtables = PQfnumber(res, "puballtables");
3729         i_pubinsert = PQfnumber(res, "pubinsert");
3730         i_pubupdate = PQfnumber(res, "pubupdate");
3731         i_pubdelete = PQfnumber(res, "pubdelete");
3732
3733         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3734
3735         for (i = 0; i < ntups; i++)
3736         {
3737                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3738                 pubinfo[i].dobj.catId.tableoid =
3739                         atooid(PQgetvalue(res, i, i_tableoid));
3740                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3741                 AssignDumpId(&pubinfo[i].dobj);
3742                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3743                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3744                 pubinfo[i].puballtables =
3745                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3746                 pubinfo[i].pubinsert =
3747                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3748                 pubinfo[i].pubupdate =
3749                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3750                 pubinfo[i].pubdelete =
3751                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3752
3753                 if (strlen(pubinfo[i].rolname) == 0)
3754                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3755                                           pubinfo[i].dobj.name);
3756
3757                 /* Decide whether we want to dump it */
3758                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3759         }
3760         PQclear(res);
3761
3762         destroyPQExpBuffer(query);
3763 }
3764
3765 /*
3766  * dumpPublication
3767  *        dump the definition of the given publication
3768  */
3769 static void
3770 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3771 {
3772         PQExpBuffer delq;
3773         PQExpBuffer query;
3774         char       *qpubname;
3775         bool            first = true;
3776
3777         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3778                 return;
3779
3780         delq = createPQExpBuffer();
3781         query = createPQExpBuffer();
3782
3783         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3784
3785         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3786                                           qpubname);
3787
3788         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3789                                           qpubname);
3790
3791         if (pubinfo->puballtables)
3792                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3793
3794         appendPQExpBufferStr(query, " WITH (publish = '");
3795         if (pubinfo->pubinsert)
3796         {
3797                 appendPQExpBufferStr(query, "insert");
3798                 first = false;
3799         }
3800
3801         if (pubinfo->pubupdate)
3802         {
3803                 if (!first)
3804                         appendPQExpBufferStr(query, ", ");
3805
3806                 appendPQExpBufferStr(query, "update");
3807                 first = false;
3808         }
3809
3810         if (pubinfo->pubdelete)
3811         {
3812                 if (!first)
3813                         appendPQExpBufferStr(query, ", ");
3814
3815                 appendPQExpBufferStr(query, "delete");
3816                 first = false;
3817         }
3818
3819         appendPQExpBufferStr(query, "');\n");
3820
3821         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3822                                  pubinfo->dobj.name,
3823                                  NULL,
3824                                  NULL,
3825                                  pubinfo->rolname, false,
3826                                  "PUBLICATION", SECTION_POST_DATA,
3827                                  query->data, delq->data, NULL,
3828                                  NULL, 0,
3829                                  NULL, NULL);
3830
3831         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3832                 dumpComment(fout, "PUBLICATION", qpubname,
3833                                         NULL, pubinfo->rolname,
3834                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3835
3836         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3837                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3838                                          NULL, pubinfo->rolname,
3839                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3840
3841         destroyPQExpBuffer(delq);
3842         destroyPQExpBuffer(query);
3843         free(qpubname);
3844 }
3845
3846 /*
3847  * getPublicationTables
3848  *        get information about publication membership for dumpable tables.
3849  */
3850 void
3851 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3852 {
3853         PQExpBuffer query;
3854         PGresult   *res;
3855         PublicationRelInfo *pubrinfo;
3856         int                     i_tableoid;
3857         int                     i_oid;
3858         int                     i_pubname;
3859         int                     i,
3860                                 j,
3861                                 ntups;
3862
3863         if (fout->remoteVersion < 100000)
3864                 return;
3865
3866         query = createPQExpBuffer();
3867
3868         for (i = 0; i < numTables; i++)
3869         {
3870                 TableInfo  *tbinfo = &tblinfo[i];
3871
3872                 /* Only plain tables can be aded to publications. */
3873                 if (tbinfo->relkind != RELKIND_RELATION)
3874                         continue;
3875
3876                 /*
3877                  * Ignore publication membership of tables whose definitions are not
3878                  * to be dumped.
3879                  */
3880                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3881                         continue;
3882
3883                 if (g_verbose)
3884                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3885                                           tbinfo->dobj.namespace->dobj.name,
3886                                           tbinfo->dobj.name);
3887
3888                 resetPQExpBuffer(query);
3889
3890                 /* Get the publication membership for the table. */
3891                 appendPQExpBuffer(query,
3892                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3893                                                   "FROM pg_publication_rel pr, pg_publication p "
3894                                                   "WHERE pr.prrelid = '%u'"
3895                                                   "  AND p.oid = pr.prpubid",
3896                                                   tbinfo->dobj.catId.oid);
3897                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3898
3899                 ntups = PQntuples(res);
3900
3901                 if (ntups == 0)
3902                 {
3903                         /*
3904                          * Table is not member of any publications. Clean up and return.
3905                          */
3906                         PQclear(res);
3907                         continue;
3908                 }
3909
3910                 i_tableoid = PQfnumber(res, "tableoid");
3911                 i_oid = PQfnumber(res, "oid");
3912                 i_pubname = PQfnumber(res, "pubname");
3913
3914                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3915
3916                 for (j = 0; j < ntups; j++)
3917                 {
3918                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3919                         pubrinfo[j].dobj.catId.tableoid =
3920                                 atooid(PQgetvalue(res, j, i_tableoid));
3921                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3922                         AssignDumpId(&pubrinfo[j].dobj);
3923                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3924                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3925                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3926                         pubrinfo[j].pubtable = tbinfo;
3927
3928                         /* Decide whether we want to dump it */
3929                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
3930                 }
3931                 PQclear(res);
3932         }
3933         destroyPQExpBuffer(query);
3934 }
3935
3936 /*
3937  * dumpPublicationTable
3938  *        dump the definition of the given publication table mapping
3939  */
3940 static void
3941 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
3942 {
3943         TableInfo  *tbinfo = pubrinfo->pubtable;
3944         PQExpBuffer query;
3945         char       *tag;
3946
3947         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3948                 return;
3949
3950         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
3951
3952         query = createPQExpBuffer();
3953
3954         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
3955                                           fmtId(pubrinfo->pubname));
3956         appendPQExpBuffer(query, " %s;\n",
3957                                           fmtQualifiedDumpable(tbinfo));
3958
3959         /*
3960          * There is no point in creating drop query as drop query as the drop is
3961          * done by table drop.
3962          */
3963         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
3964                                  tag,
3965                                  tbinfo->dobj.namespace->dobj.name,
3966                                  NULL,
3967                                  "", false,
3968                                  "PUBLICATION TABLE", SECTION_POST_DATA,
3969                                  query->data, "", NULL,
3970                                  NULL, 0,
3971                                  NULL, NULL);
3972
3973         free(tag);
3974         destroyPQExpBuffer(query);
3975 }
3976
3977 /*
3978  * Is the currently connected user a superuser?
3979  */
3980 static bool
3981 is_superuser(Archive *fout)
3982 {
3983         ArchiveHandle *AH = (ArchiveHandle *) fout;
3984         const char *val;
3985
3986         val = PQparameterStatus(AH->connection, "is_superuser");
3987
3988         if (val && strcmp(val, "on") == 0)
3989                 return true;
3990
3991         return false;
3992 }
3993
3994 /*
3995  * getSubscriptions
3996  *        get information about subscriptions
3997  */
3998 void
3999 getSubscriptions(Archive *fout)
4000 {
4001         DumpOptions *dopt = fout->dopt;
4002         PQExpBuffer query;
4003         PGresult   *res;
4004         SubscriptionInfo *subinfo;
4005         int                     i_tableoid;
4006         int                     i_oid;
4007         int                     i_subname;
4008         int                     i_rolname;
4009         int                     i_subconninfo;
4010         int                     i_subslotname;
4011         int                     i_subsynccommit;
4012         int                     i_subpublications;
4013         int                     i,
4014                                 ntups;
4015
4016         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4017                 return;
4018
4019         if (!is_superuser(fout))
4020         {
4021                 int                     n;
4022
4023                 res = ExecuteSqlQuery(fout,
4024                                                           "SELECT count(*) FROM pg_subscription "
4025                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4026                                                           "                 WHERE datname = current_database())",
4027                                                           PGRES_TUPLES_OK);
4028                 n = atoi(PQgetvalue(res, 0, 0));
4029                 if (n > 0)
4030                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4031                 PQclear(res);
4032                 return;
4033         }
4034
4035         query = createPQExpBuffer();
4036
4037         resetPQExpBuffer(query);
4038
4039         /* Get the subscriptions in current database. */
4040         appendPQExpBuffer(query,
4041                                           "SELECT s.tableoid, s.oid, s.subname,"
4042                                           "(%s s.subowner) AS rolname, "
4043                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4044                                           " s.subpublications "
4045                                           "FROM pg_subscription s "
4046                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4047                                           "                   WHERE datname = current_database())",
4048                                           username_subquery);
4049         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4050
4051         ntups = PQntuples(res);
4052
4053         i_tableoid = PQfnumber(res, "tableoid");
4054         i_oid = PQfnumber(res, "oid");
4055         i_subname = PQfnumber(res, "subname");
4056         i_rolname = PQfnumber(res, "rolname");
4057         i_subconninfo = PQfnumber(res, "subconninfo");
4058         i_subslotname = PQfnumber(res, "subslotname");
4059         i_subsynccommit = PQfnumber(res, "subsynccommit");
4060         i_subpublications = PQfnumber(res, "subpublications");
4061
4062         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4063
4064         for (i = 0; i < ntups; i++)
4065         {
4066                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4067                 subinfo[i].dobj.catId.tableoid =
4068                         atooid(PQgetvalue(res, i, i_tableoid));
4069                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4070                 AssignDumpId(&subinfo[i].dobj);
4071                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4072                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4073                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4074                 if (PQgetisnull(res, i, i_subslotname))
4075                         subinfo[i].subslotname = NULL;
4076                 else
4077                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4078                 subinfo[i].subsynccommit =
4079                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4080                 subinfo[i].subpublications =
4081                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4082
4083                 if (strlen(subinfo[i].rolname) == 0)
4084                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4085                                           subinfo[i].dobj.name);
4086
4087                 /* Decide whether we want to dump it */
4088                 selectDumpableObject(&(subinfo[i].dobj), fout);
4089         }
4090         PQclear(res);
4091
4092         destroyPQExpBuffer(query);
4093 }
4094
4095 /*
4096  * dumpSubscription
4097  *        dump the definition of the given subscription
4098  */
4099 static void
4100 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4101 {
4102         PQExpBuffer delq;
4103         PQExpBuffer query;
4104         PQExpBuffer publications;
4105         char       *qsubname;
4106         char      **pubnames = NULL;
4107         int                     npubnames = 0;
4108         int                     i;
4109
4110         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4111                 return;
4112
4113         delq = createPQExpBuffer();
4114         query = createPQExpBuffer();
4115
4116         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4117
4118         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4119                                           qsubname);
4120
4121         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4122                                           qsubname);
4123         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4124
4125         /* Build list of quoted publications and append them to query. */
4126         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4127         {
4128                 write_msg(NULL,
4129                                   "WARNING: could not parse subpublications array\n");
4130                 if (pubnames)
4131                         free(pubnames);
4132                 pubnames = NULL;
4133                 npubnames = 0;
4134         }
4135
4136         publications = createPQExpBuffer();
4137         for (i = 0; i < npubnames; i++)
4138         {
4139                 if (i > 0)
4140                         appendPQExpBufferStr(publications, ", ");
4141
4142                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4143         }
4144
4145         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4146         if (subinfo->subslotname)
4147                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4148         else
4149                 appendPQExpBufferStr(query, "NONE");
4150
4151         if (strcmp(subinfo->subsynccommit, "off") != 0)
4152                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4153
4154         appendPQExpBufferStr(query, ");\n");
4155
4156         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4157                                  subinfo->dobj.name,
4158                                  NULL,
4159                                  NULL,
4160                                  subinfo->rolname, false,
4161                                  "SUBSCRIPTION", SECTION_POST_DATA,
4162                                  query->data, delq->data, NULL,
4163                                  NULL, 0,
4164                                  NULL, NULL);
4165
4166         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4167                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4168                                         NULL, subinfo->rolname,
4169                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4170
4171         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4172                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4173                                          NULL, subinfo->rolname,
4174                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4175
4176         destroyPQExpBuffer(publications);
4177         if (pubnames)
4178                 free(pubnames);
4179
4180         destroyPQExpBuffer(delq);
4181         destroyPQExpBuffer(query);
4182         free(qsubname);
4183 }
4184
4185 static void
4186 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4187                                                                                  PQExpBuffer upgrade_buffer,
4188                                                                                  Oid pg_type_oid,
4189                                                                                  bool force_array_type)
4190 {
4191         PQExpBuffer upgrade_query = createPQExpBuffer();
4192         PGresult   *res;
4193         Oid                     pg_type_array_oid;
4194
4195         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4196         appendPQExpBuffer(upgrade_buffer,
4197                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4198                                           pg_type_oid);
4199
4200         /* we only support old >= 8.3 for binary upgrades */
4201         appendPQExpBuffer(upgrade_query,
4202                                           "SELECT typarray "
4203                                           "FROM pg_catalog.pg_type "
4204                                           "WHERE oid = '%u'::pg_catalog.oid;",
4205                                           pg_type_oid);
4206
4207         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4208
4209         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4210
4211         PQclear(res);
4212
4213         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4214         {
4215                 /*
4216                  * If the old version didn't assign an array type, but the new version
4217                  * does, we must select an unused type OID to assign.  This currently
4218                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4219                  *
4220                  * Note: local state here is kind of ugly, but we must have some,
4221                  * since we mustn't choose the same unused OID more than once.
4222                  */
4223                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4224                 bool            is_dup;
4225
4226                 do
4227                 {
4228                         ++next_possible_free_oid;
4229                         printfPQExpBuffer(upgrade_query,
4230                                                           "SELECT EXISTS(SELECT 1 "
4231                                                           "FROM pg_catalog.pg_type "
4232                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4233                                                           next_possible_free_oid);
4234                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4235                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4236                         PQclear(res);
4237                 } while (is_dup);
4238
4239                 pg_type_array_oid = next_possible_free_oid;
4240         }
4241
4242         if (OidIsValid(pg_type_array_oid))
4243         {
4244                 appendPQExpBufferStr(upgrade_buffer,
4245                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4246                 appendPQExpBuffer(upgrade_buffer,
4247                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4248                                                   pg_type_array_oid);
4249         }
4250
4251         destroyPQExpBuffer(upgrade_query);
4252 }
4253
4254 static bool
4255 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4256                                                                                 PQExpBuffer upgrade_buffer,
4257                                                                                 Oid pg_rel_oid)
4258 {
4259         PQExpBuffer upgrade_query = createPQExpBuffer();
4260         PGresult   *upgrade_res;
4261         Oid                     pg_type_oid;
4262         bool            toast_set = false;
4263
4264         /* we only support old >= 8.3 for binary upgrades */
4265         appendPQExpBuffer(upgrade_query,
4266                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4267                                           "FROM pg_catalog.pg_class c "
4268                                           "LEFT JOIN pg_catalog.pg_class t ON "
4269                                           "  (c.reltoastrelid = t.oid) "
4270                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4271                                           pg_rel_oid);
4272
4273         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4274
4275         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4276
4277         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4278                                                                                          pg_type_oid, false);
4279
4280         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4281         {
4282                 /* Toast tables do not have pg_type array rows */
4283                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4284                                                                                                                   PQfnumber(upgrade_res, "trel")));
4285
4286                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4287                 appendPQExpBuffer(upgrade_buffer,
4288                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4289                                                   pg_type_toast_oid);
4290
4291                 toast_set = true;
4292         }
4293
4294         PQclear(upgrade_res);
4295         destroyPQExpBuffer(upgrade_query);
4296
4297         return toast_set;
4298 }
4299
4300 static void
4301 binary_upgrade_set_pg_class_oids(Archive *fout,
4302                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4303                                                                  bool is_index)
4304 {
4305         PQExpBuffer upgrade_query = createPQExpBuffer();
4306         PGresult   *upgrade_res;
4307         Oid                     pg_class_reltoastrelid;
4308         Oid                     pg_index_indexrelid;
4309
4310         appendPQExpBuffer(upgrade_query,
4311                                           "SELECT c.reltoastrelid, i.indexrelid "
4312                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4313                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4314                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4315                                           pg_class_oid);
4316
4317         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4318
4319         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4320         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4321
4322         appendPQExpBufferStr(upgrade_buffer,
4323                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4324
4325         if (!is_index)
4326         {
4327                 appendPQExpBuffer(upgrade_buffer,
4328                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4329                                                   pg_class_oid);
4330                 /* only tables have toast tables, not indexes */
4331                 if (OidIsValid(pg_class_reltoastrelid))
4332                 {
4333                         /*
4334                          * One complexity is that the table definition might not require
4335                          * the creation of a TOAST table, and the TOAST table might have
4336                          * been created long after table creation, when the table was
4337                          * loaded with wide data.  By setting the TOAST oid we force
4338                          * creation of the TOAST heap and TOAST index by the backend so we
4339                          * can cleanly copy the files during binary upgrade.
4340                          */
4341
4342                         appendPQExpBuffer(upgrade_buffer,
4343                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4344                                                           pg_class_reltoastrelid);
4345
4346                         /* every toast table has an index */
4347                         appendPQExpBuffer(upgrade_buffer,
4348                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4349                                                           pg_index_indexrelid);
4350                 }
4351         }
4352         else
4353                 appendPQExpBuffer(upgrade_buffer,
4354                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4355                                                   pg_class_oid);
4356
4357         appendPQExpBufferChar(upgrade_buffer, '\n');
4358
4359         PQclear(upgrade_res);
4360         destroyPQExpBuffer(upgrade_query);
4361 }
4362
4363 /*
4364  * If the DumpableObject is a member of an extension, add a suitable
4365  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4366  *
4367  * For somewhat historical reasons, objname should already be quoted,
4368  * but not objnamespace (if any).
4369  */
4370 static void
4371 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4372                                                                 DumpableObject *dobj,
4373                                                                 const char *objtype,
4374                                                                 const char *objname,
4375                                                                 const char *objnamespace)
4376 {
4377         DumpableObject *extobj = NULL;
4378         int                     i;
4379
4380         if (!dobj->ext_member)
4381                 return;
4382
4383         /*
4384          * Find the parent extension.  We could avoid this search if we wanted to
4385          * add a link field to DumpableObject, but the space costs of that would
4386          * be considerable.  We assume that member objects could only have a
4387          * direct dependency on their own extension, not any others.
4388          */
4389         for (i = 0; i < dobj->nDeps; i++)
4390         {
4391                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4392                 if (extobj && extobj->objType == DO_EXTENSION)
4393                         break;
4394                 extobj = NULL;
4395         }
4396         if (extobj == NULL)
4397                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4398                                           objtype, objname);
4399
4400         appendPQExpBufferStr(upgrade_buffer,
4401                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4402         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4403                                           fmtId(extobj->name),
4404                                           objtype);
4405         if (objnamespace && *objnamespace)
4406                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4407         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4408 }
4409
4410 /*
4411  * getNamespaces:
4412  *        read all namespaces in the system catalogs and return them in the
4413  * NamespaceInfo* structure
4414  *
4415  *      numNamespaces is set to the number of namespaces read in
4416  */
4417 NamespaceInfo *
4418 getNamespaces(Archive *fout, int *numNamespaces)
4419 {
4420         DumpOptions *dopt = fout->dopt;
4421         PGresult   *res;
4422         int                     ntups;
4423         int                     i;
4424         PQExpBuffer query;
4425         NamespaceInfo *nsinfo;
4426         int                     i_tableoid;
4427         int                     i_oid;
4428         int                     i_nspname;
4429         int                     i_rolname;
4430         int                     i_nspacl;
4431         int                     i_rnspacl;
4432         int                     i_initnspacl;
4433         int                     i_initrnspacl;
4434
4435         query = createPQExpBuffer();
4436
4437         /*
4438          * we fetch all namespaces including system ones, so that every object we
4439          * read in can be linked to a containing namespace.
4440          */
4441         if (fout->remoteVersion >= 90600)
4442         {
4443                 PQExpBuffer acl_subquery = createPQExpBuffer();
4444                 PQExpBuffer racl_subquery = createPQExpBuffer();
4445                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4446                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4447
4448                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4449                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4450                                                 dopt->binary_upgrade);
4451
4452                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4453                                                   "(%s nspowner) AS rolname, "
4454                                                   "%s as nspacl, "
4455                                                   "%s as rnspacl, "
4456                                                   "%s as initnspacl, "
4457                                                   "%s as initrnspacl "
4458                                                   "FROM pg_namespace n "
4459                                                   "LEFT JOIN pg_init_privs pip "
4460                                                   "ON (n.oid = pip.objoid "
4461                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4462                                                   "AND pip.objsubid = 0",
4463                                                   username_subquery,
4464                                                   acl_subquery->data,
4465                                                   racl_subquery->data,
4466                                                   init_acl_subquery->data,
4467                                                   init_racl_subquery->data);
4468
4469                 appendPQExpBuffer(query, ") ");
4470
4471                 destroyPQExpBuffer(acl_subquery);
4472                 destroyPQExpBuffer(racl_subquery);
4473                 destroyPQExpBuffer(init_acl_subquery);
4474                 destroyPQExpBuffer(init_racl_subquery);
4475         }
4476         else
4477                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4478                                                   "(%s nspowner) AS rolname, "
4479                                                   "nspacl, NULL as rnspacl, "
4480                                                   "NULL AS initnspacl, NULL as initrnspacl "
4481                                                   "FROM pg_namespace",
4482                                                   username_subquery);
4483
4484         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4485
4486         ntups = PQntuples(res);
4487
4488         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4489
4490         i_tableoid = PQfnumber(res, "tableoid");
4491         i_oid = PQfnumber(res, "oid");
4492         i_nspname = PQfnumber(res, "nspname");
4493         i_rolname = PQfnumber(res, "rolname");
4494         i_nspacl = PQfnumber(res, "nspacl");
4495         i_rnspacl = PQfnumber(res, "rnspacl");
4496         i_initnspacl = PQfnumber(res, "initnspacl");
4497         i_initrnspacl = PQfnumber(res, "initrnspacl");
4498
4499         for (i = 0; i < ntups; i++)
4500         {
4501                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4502                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4503                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4504                 AssignDumpId(&nsinfo[i].dobj);
4505                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4506                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4507                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4508                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4509                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4510                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4511
4512                 /* Decide whether to dump this namespace */
4513                 selectDumpableNamespace(&nsinfo[i], fout);
4514
4515                 /*
4516                  * Do not try to dump ACL if the ACL is empty or the default.
4517                  *
4518                  * This is useful because, for some schemas/objects, the only
4519                  * component we are going to try and dump is the ACL and if we can
4520                  * remove that then 'dump' goes to zero/false and we don't consider
4521                  * this object for dumping at all later on.
4522                  */
4523                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4524                         PQgetisnull(res, i, i_initnspacl) &&
4525                         PQgetisnull(res, i, i_initrnspacl))
4526                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4527
4528                 if (strlen(nsinfo[i].rolname) == 0)
4529                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4530                                           nsinfo[i].dobj.name);
4531         }
4532
4533         PQclear(res);
4534         destroyPQExpBuffer(query);
4535
4536         *numNamespaces = ntups;
4537
4538         return nsinfo;
4539 }
4540
4541 /*
4542  * findNamespace:
4543  *              given a namespace OID, look up the info read by getNamespaces
4544  */
4545 static NamespaceInfo *
4546 findNamespace(Archive *fout, Oid nsoid)
4547 {
4548         NamespaceInfo *nsinfo;
4549
4550         nsinfo = findNamespaceByOid(nsoid);
4551         if (nsinfo == NULL)
4552                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4553         return nsinfo;
4554 }
4555
4556 /*
4557  * getExtensions:
4558  *        read all extensions in the system catalogs and return them in the
4559  * ExtensionInfo* structure
4560  *
4561  *      numExtensions is set to the number of extensions read in
4562  */
4563 ExtensionInfo *
4564 getExtensions(Archive *fout, int *numExtensions)
4565 {
4566         DumpOptions *dopt = fout->dopt;
4567         PGresult   *res;
4568         int                     ntups;
4569         int                     i;
4570         PQExpBuffer query;
4571         ExtensionInfo *extinfo;
4572         int                     i_tableoid;
4573         int                     i_oid;
4574         int                     i_extname;
4575         int                     i_nspname;
4576         int                     i_extrelocatable;
4577         int                     i_extversion;
4578         int                     i_extconfig;
4579         int                     i_extcondition;
4580
4581         /*
4582          * Before 9.1, there are no extensions.
4583          */
4584         if (fout->remoteVersion < 90100)
4585         {
4586                 *numExtensions = 0;
4587                 return NULL;
4588         }
4589
4590         query = createPQExpBuffer();
4591
4592         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4593                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4594                                                  "FROM pg_extension x "
4595                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4596
4597         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4598
4599         ntups = PQntuples(res);
4600
4601         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4602
4603         i_tableoid = PQfnumber(res, "tableoid");
4604         i_oid = PQfnumber(res, "oid");
4605         i_extname = PQfnumber(res, "extname");
4606         i_nspname = PQfnumber(res, "nspname");
4607         i_extrelocatable = PQfnumber(res, "extrelocatable");
4608         i_extversion = PQfnumber(res, "extversion");
4609         i_extconfig = PQfnumber(res, "extconfig");
4610         i_extcondition = PQfnumber(res, "extcondition");
4611
4612         for (i = 0; i < ntups; i++)
4613         {
4614                 extinfo[i].dobj.objType = DO_EXTENSION;
4615                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4616                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4617                 AssignDumpId(&extinfo[i].dobj);
4618                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4619                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4620                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4621                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4622                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4623                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4624
4625                 /* Decide whether we want to dump it */
4626                 selectDumpableExtension(&(extinfo[i]), dopt);
4627         }
4628
4629         PQclear(res);
4630         destroyPQExpBuffer(query);
4631
4632         *numExtensions = ntups;
4633
4634         return extinfo;
4635 }
4636
4637 /*
4638  * getTypes:
4639  *        read all types in the system catalogs and return them in the
4640  * TypeInfo* structure
4641  *
4642  *      numTypes is set to the number of types read in
4643  *
4644  * NB: this must run after getFuncs() because we assume we can do
4645  * findFuncByOid().
4646  */
4647 TypeInfo *
4648 getTypes(Archive *fout, int *numTypes)
4649 {
4650         DumpOptions *dopt = fout->dopt;
4651         PGresult   *res;
4652         int                     ntups;
4653         int                     i;
4654         PQExpBuffer query = createPQExpBuffer();
4655         TypeInfo   *tyinfo;
4656         ShellTypeInfo *stinfo;
4657         int                     i_tableoid;
4658         int                     i_oid;
4659         int                     i_typname;
4660         int                     i_typnamespace;
4661         int                     i_typacl;
4662         int                     i_rtypacl;
4663         int                     i_inittypacl;
4664         int                     i_initrtypacl;
4665         int                     i_rolname;
4666         int                     i_typelem;
4667         int                     i_typrelid;
4668         int                     i_typrelkind;
4669         int                     i_typtype;
4670         int                     i_typisdefined;
4671         int                     i_isarray;
4672
4673         /*
4674          * we include even the built-in types because those may be used as array
4675          * elements by user-defined types
4676          *
4677          * we filter out the built-in types when we dump out the types
4678          *
4679          * same approach for undefined (shell) types and array types
4680          *
4681          * Note: as of 8.3 we can reliably detect whether a type is an
4682          * auto-generated array type by checking the element type's typarray.
4683          * (Before that the test is capable of generating false positives.) We
4684          * still check for name beginning with '_', though, so as to avoid the
4685          * cost of the subselect probe for all standard types.  This would have to
4686          * be revisited if the backend ever allows renaming of array types.
4687          */
4688
4689         if (fout->remoteVersion >= 90600)
4690         {
4691                 PQExpBuffer acl_subquery = createPQExpBuffer();
4692                 PQExpBuffer racl_subquery = createPQExpBuffer();
4693                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4694                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4695
4696                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4697                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4698                                                 dopt->binary_upgrade);
4699
4700                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4701                                                   "t.typnamespace, "
4702                                                   "%s AS typacl, "
4703                                                   "%s AS rtypacl, "
4704                                                   "%s AS inittypacl, "
4705                                                   "%s AS initrtypacl, "
4706                                                   "(%s t.typowner) AS rolname, "
4707                                                   "t.typelem, t.typrelid, "
4708                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4709                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4710                                                   "t.typtype, t.typisdefined, "
4711                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4712                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4713                                                   "FROM pg_type t "
4714                                                   "LEFT JOIN pg_init_privs pip ON "
4715                                                   "(t.oid = pip.objoid "
4716                                                   "AND pip.classoid = 'pg_type'::regclass "
4717                                                   "AND pip.objsubid = 0) ",
4718                                                   acl_subquery->data,
4719                                                   racl_subquery->data,
4720                                                   initacl_subquery->data,
4721                                                   initracl_subquery->data,
4722                                                   username_subquery);
4723
4724                 destroyPQExpBuffer(acl_subquery);
4725                 destroyPQExpBuffer(racl_subquery);
4726                 destroyPQExpBuffer(initacl_subquery);
4727                 destroyPQExpBuffer(initracl_subquery);
4728         }
4729         else if (fout->remoteVersion >= 90200)
4730         {
4731                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4732                                                   "typnamespace, typacl, NULL as rtypacl, "
4733                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4734                                                   "(%s typowner) AS rolname, "
4735                                                   "typelem, typrelid, "
4736                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4737                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4738                                                   "typtype, typisdefined, "
4739                                                   "typname[0] = '_' AND typelem != 0 AND "
4740                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4741                                                   "FROM pg_type",
4742                                                   username_subquery);
4743         }
4744         else if (fout->remoteVersion >= 80300)
4745         {
4746                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4747                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4748                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4749                                                   "(%s typowner) AS rolname, "
4750                                                   "typelem, typrelid, "
4751                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4752                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4753                                                   "typtype, typisdefined, "
4754                                                   "typname[0] = '_' AND typelem != 0 AND "
4755                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4756                                                   "FROM pg_type",
4757                                                   username_subquery);
4758         }
4759         else
4760         {
4761                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4762                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4763                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4764                                                   "(%s typowner) AS rolname, "
4765                                                   "typelem, typrelid, "
4766                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4767                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4768                                                   "typtype, typisdefined, "
4769                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4770                                                   "FROM pg_type",
4771                                                   username_subquery);
4772         }
4773
4774         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4775
4776         ntups = PQntuples(res);
4777
4778         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4779
4780         i_tableoid = PQfnumber(res, "tableoid");
4781         i_oid = PQfnumber(res, "oid");
4782         i_typname = PQfnumber(res, "typname");
4783         i_typnamespace = PQfnumber(res, "typnamespace");
4784         i_typacl = PQfnumber(res, "typacl");
4785         i_rtypacl = PQfnumber(res, "rtypacl");
4786         i_inittypacl = PQfnumber(res, "inittypacl");
4787         i_initrtypacl = PQfnumber(res, "initrtypacl");
4788         i_rolname = PQfnumber(res, "rolname");
4789         i_typelem = PQfnumber(res, "typelem");
4790         i_typrelid = PQfnumber(res, "typrelid");
4791         i_typrelkind = PQfnumber(res, "typrelkind");
4792         i_typtype = PQfnumber(res, "typtype");
4793         i_typisdefined = PQfnumber(res, "typisdefined");
4794         i_isarray = PQfnumber(res, "isarray");
4795
4796         for (i = 0; i < ntups; i++)
4797         {
4798                 tyinfo[i].dobj.objType = DO_TYPE;
4799                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4800                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4801                 AssignDumpId(&tyinfo[i].dobj);
4802                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4803                 tyinfo[i].dobj.namespace =
4804                         findNamespace(fout,
4805                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4806                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4807                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4808                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4809                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4810                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4811                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4812                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4813                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4814                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4815                 tyinfo[i].shellType = NULL;
4816
4817                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4818                         tyinfo[i].isDefined = true;
4819                 else
4820                         tyinfo[i].isDefined = false;
4821
4822                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4823                         tyinfo[i].isArray = true;
4824                 else
4825                         tyinfo[i].isArray = false;
4826
4827                 /* Decide whether we want to dump it */
4828                 selectDumpableType(&tyinfo[i], fout);
4829
4830                 /* Do not try to dump ACL if no ACL exists. */
4831                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4832                         PQgetisnull(res, i, i_inittypacl) &&
4833                         PQgetisnull(res, i, i_initrtypacl))
4834                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4835
4836                 /*
4837                  * If it's a domain, fetch info about its constraints, if any
4838                  */
4839                 tyinfo[i].nDomChecks = 0;
4840                 tyinfo[i].domChecks = NULL;
4841                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4842                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4843                         getDomainConstraints(fout, &(tyinfo[i]));
4844
4845                 /*
4846                  * If it's a base type, make a DumpableObject representing a shell
4847                  * definition of the type.  We will need to dump that ahead of the I/O
4848                  * functions for the type.  Similarly, range types need a shell
4849                  * definition in case they have a canonicalize function.
4850                  *
4851                  * Note: the shell type doesn't have a catId.  You might think it
4852                  * should copy the base type's catId, but then it might capture the
4853                  * pg_depend entries for the type, which we don't want.
4854                  */
4855                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4856                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4857                          tyinfo[i].typtype == TYPTYPE_RANGE))
4858                 {
4859                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4860                         stinfo->dobj.objType = DO_SHELL_TYPE;
4861                         stinfo->dobj.catId = nilCatalogId;
4862                         AssignDumpId(&stinfo->dobj);
4863                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4864                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4865                         stinfo->baseType = &(tyinfo[i]);
4866                         tyinfo[i].shellType = stinfo;
4867
4868                         /*
4869                          * Initially mark the shell type as not to be dumped.  We'll only
4870                          * dump it if the I/O or canonicalize functions need to be dumped;
4871                          * this is taken care of while sorting dependencies.
4872                          */
4873                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4874                 }
4875
4876                 if (strlen(tyinfo[i].rolname) == 0)
4877                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4878                                           tyinfo[i].dobj.name);
4879         }
4880
4881         *numTypes = ntups;
4882
4883         PQclear(res);
4884
4885         destroyPQExpBuffer(query);
4886
4887         return tyinfo;
4888 }
4889
4890 /*
4891  * getOperators:
4892  *        read all operators in the system catalogs and return them in the
4893  * OprInfo* structure
4894  *
4895  *      numOprs is set to the number of operators read in
4896  */
4897 OprInfo *
4898 getOperators(Archive *fout, int *numOprs)
4899 {
4900         PGresult   *res;
4901         int                     ntups;
4902         int                     i;
4903         PQExpBuffer query = createPQExpBuffer();
4904         OprInfo    *oprinfo;
4905         int                     i_tableoid;
4906         int                     i_oid;
4907         int                     i_oprname;
4908         int                     i_oprnamespace;
4909         int                     i_rolname;
4910         int                     i_oprkind;
4911         int                     i_oprcode;
4912
4913         /*
4914          * find all operators, including builtin operators; we filter out
4915          * system-defined operators at dump-out time.
4916          */
4917
4918         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4919                                           "oprnamespace, "
4920                                           "(%s oprowner) AS rolname, "
4921                                           "oprkind, "
4922                                           "oprcode::oid AS oprcode "
4923                                           "FROM pg_operator",
4924                                           username_subquery);
4925
4926         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4927
4928         ntups = PQntuples(res);
4929         *numOprs = ntups;
4930
4931         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4932
4933         i_tableoid = PQfnumber(res, "tableoid");
4934         i_oid = PQfnumber(res, "oid");
4935         i_oprname = PQfnumber(res, "oprname");
4936         i_oprnamespace = PQfnumber(res, "oprnamespace");
4937         i_rolname = PQfnumber(res, "rolname");
4938         i_oprkind = PQfnumber(res, "oprkind");
4939         i_oprcode = PQfnumber(res, "oprcode");
4940
4941         for (i = 0; i < ntups; i++)
4942         {
4943                 oprinfo[i].dobj.objType = DO_OPERATOR;
4944                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4945                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4946                 AssignDumpId(&oprinfo[i].dobj);
4947                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4948                 oprinfo[i].dobj.namespace =
4949                         findNamespace(fout,
4950                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
4951                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4952                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4953                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4954
4955                 /* Decide whether we want to dump it */
4956                 selectDumpableObject(&(oprinfo[i].dobj), fout);
4957
4958                 /* Operators do not currently have ACLs. */
4959                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4960
4961                 if (strlen(oprinfo[i].rolname) == 0)
4962                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4963                                           oprinfo[i].dobj.name);
4964         }
4965
4966         PQclear(res);
4967
4968         destroyPQExpBuffer(query);
4969
4970         return oprinfo;
4971 }
4972
4973 /*
4974  * getCollations:
4975  *        read all collations in the system catalogs and return them in the
4976  * CollInfo* structure
4977  *
4978  *      numCollations is set to the number of collations read in
4979  */
4980 CollInfo *
4981 getCollations(Archive *fout, int *numCollations)
4982 {
4983         PGresult   *res;
4984         int                     ntups;
4985         int                     i;
4986         PQExpBuffer query;
4987         CollInfo   *collinfo;
4988         int                     i_tableoid;
4989         int                     i_oid;
4990         int                     i_collname;
4991         int                     i_collnamespace;
4992         int                     i_rolname;
4993
4994         /* Collations didn't exist pre-9.1 */
4995         if (fout->remoteVersion < 90100)
4996         {
4997                 *numCollations = 0;
4998                 return NULL;
4999         }
5000
5001         query = createPQExpBuffer();
5002
5003         /*
5004          * find all collations, including builtin collations; we filter out
5005          * system-defined collations at dump-out time.
5006          */
5007
5008         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5009                                           "collnamespace, "
5010                                           "(%s collowner) AS rolname "
5011                                           "FROM pg_collation",
5012                                           username_subquery);
5013
5014         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5015
5016         ntups = PQntuples(res);
5017         *numCollations = ntups;
5018
5019         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5020
5021         i_tableoid = PQfnumber(res, "tableoid");
5022         i_oid = PQfnumber(res, "oid");
5023         i_collname = PQfnumber(res, "collname");
5024         i_collnamespace = PQfnumber(res, "collnamespace");
5025         i_rolname = PQfnumber(res, "rolname");
5026
5027         for (i = 0; i < ntups; i++)
5028         {
5029                 collinfo[i].dobj.objType = DO_COLLATION;
5030                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5031                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5032                 AssignDumpId(&collinfo[i].dobj);
5033                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5034                 collinfo[i].dobj.namespace =
5035                         findNamespace(fout,
5036                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5037                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5038
5039                 /* Decide whether we want to dump it */
5040                 selectDumpableObject(&(collinfo[i].dobj), fout);
5041
5042                 /* Collations do not currently have ACLs. */
5043                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5044         }
5045
5046         PQclear(res);
5047
5048         destroyPQExpBuffer(query);
5049
5050         return collinfo;
5051 }
5052
5053 /*
5054  * getConversions:
5055  *        read all conversions in the system catalogs and return them in the
5056  * ConvInfo* structure
5057  *
5058  *      numConversions is set to the number of conversions read in
5059  */
5060 ConvInfo *
5061 getConversions(Archive *fout, int *numConversions)
5062 {
5063         PGresult   *res;
5064         int                     ntups;
5065         int                     i;
5066         PQExpBuffer query;
5067         ConvInfo   *convinfo;
5068         int                     i_tableoid;
5069         int                     i_oid;
5070         int                     i_conname;
5071         int                     i_connamespace;
5072         int                     i_rolname;
5073
5074         query = createPQExpBuffer();
5075
5076         /*
5077          * find all conversions, including builtin conversions; we filter out
5078          * system-defined conversions at dump-out time.
5079          */
5080
5081         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5082                                           "connamespace, "
5083                                           "(%s conowner) AS rolname "
5084                                           "FROM pg_conversion",
5085                                           username_subquery);
5086
5087         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5088
5089         ntups = PQntuples(res);
5090         *numConversions = ntups;
5091
5092         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5093
5094         i_tableoid = PQfnumber(res, "tableoid");
5095         i_oid = PQfnumber(res, "oid");
5096         i_conname = PQfnumber(res, "conname");
5097         i_connamespace = PQfnumber(res, "connamespace");
5098         i_rolname = PQfnumber(res, "rolname");
5099
5100         for (i = 0; i < ntups; i++)
5101         {
5102                 convinfo[i].dobj.objType = DO_CONVERSION;
5103                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5104                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5105                 AssignDumpId(&convinfo[i].dobj);
5106                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5107                 convinfo[i].dobj.namespace =
5108                         findNamespace(fout,
5109                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5110                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5111
5112                 /* Decide whether we want to dump it */
5113                 selectDumpableObject(&(convinfo[i].dobj), fout);
5114
5115                 /* Conversions do not currently have ACLs. */
5116                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5117         }
5118
5119         PQclear(res);
5120
5121         destroyPQExpBuffer(query);
5122
5123         return convinfo;
5124 }
5125
5126 /*
5127  * getAccessMethods:
5128  *        read all user-defined access methods in the system catalogs and return
5129  *        them in the AccessMethodInfo* structure
5130  *
5131  *      numAccessMethods is set to the number of access methods read in
5132  */
5133 AccessMethodInfo *
5134 getAccessMethods(Archive *fout, int *numAccessMethods)
5135 {
5136         PGresult   *res;
5137         int                     ntups;
5138         int                     i;
5139         PQExpBuffer query;
5140         AccessMethodInfo *aminfo;
5141         int                     i_tableoid;
5142         int                     i_oid;
5143         int                     i_amname;
5144         int                     i_amhandler;
5145         int                     i_amtype;
5146
5147         /* Before 9.6, there are no user-defined access methods */
5148         if (fout->remoteVersion < 90600)
5149         {
5150                 *numAccessMethods = 0;
5151                 return NULL;
5152         }
5153
5154         query = createPQExpBuffer();
5155
5156         /* Select all access methods from pg_am table */
5157         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5158                                           "amhandler::pg_catalog.regproc AS amhandler "
5159                                           "FROM pg_am");
5160
5161         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5162
5163         ntups = PQntuples(res);
5164         *numAccessMethods = ntups;
5165
5166         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5167
5168         i_tableoid = PQfnumber(res, "tableoid");
5169         i_oid = PQfnumber(res, "oid");
5170         i_amname = PQfnumber(res, "amname");
5171         i_amhandler = PQfnumber(res, "amhandler");
5172         i_amtype = PQfnumber(res, "amtype");
5173
5174         for (i = 0; i < ntups; i++)
5175         {
5176                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5177                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5178                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5179                 AssignDumpId(&aminfo[i].dobj);
5180                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5181                 aminfo[i].dobj.namespace = NULL;
5182                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5183                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5184
5185                 /* Decide whether we want to dump it */
5186                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5187
5188                 /* Access methods do not currently have ACLs. */
5189                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5190         }
5191
5192         PQclear(res);
5193
5194         destroyPQExpBuffer(query);
5195
5196         return aminfo;
5197 }
5198
5199
5200 /*
5201  * getOpclasses:
5202  *        read all opclasses in the system catalogs and return them in the
5203  * OpclassInfo* structure
5204  *
5205  *      numOpclasses is set to the number of opclasses read in
5206  */
5207 OpclassInfo *
5208 getOpclasses(Archive *fout, int *numOpclasses)
5209 {
5210         PGresult   *res;
5211         int                     ntups;
5212         int                     i;
5213         PQExpBuffer query = createPQExpBuffer();
5214         OpclassInfo *opcinfo;
5215         int                     i_tableoid;
5216         int                     i_oid;
5217         int                     i_opcname;
5218         int                     i_opcnamespace;
5219         int                     i_rolname;
5220
5221         /*
5222          * find all opclasses, including builtin opclasses; we filter out
5223          * system-defined opclasses at dump-out time.
5224          */
5225
5226         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5227                                           "opcnamespace, "
5228                                           "(%s opcowner) AS rolname "
5229                                           "FROM pg_opclass",
5230                                           username_subquery);
5231
5232         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5233
5234         ntups = PQntuples(res);
5235         *numOpclasses = ntups;
5236
5237         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5238
5239         i_tableoid = PQfnumber(res, "tableoid");
5240         i_oid = PQfnumber(res, "oid");
5241         i_opcname = PQfnumber(res, "opcname");
5242         i_opcnamespace = PQfnumber(res, "opcnamespace");
5243         i_rolname = PQfnumber(res, "rolname");
5244
5245         for (i = 0; i < ntups; i++)
5246         {
5247                 opcinfo[i].dobj.objType = DO_OPCLASS;
5248                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5249                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5250                 AssignDumpId(&opcinfo[i].dobj);
5251                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5252                 opcinfo[i].dobj.namespace =
5253                         findNamespace(fout,
5254                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5255                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5256
5257                 /* Decide whether we want to dump it */
5258                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5259
5260                 /* Op Classes do not currently have ACLs. */
5261                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5262
5263                 if (strlen(opcinfo[i].rolname) == 0)
5264                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5265                                           opcinfo[i].dobj.name);
5266         }
5267
5268         PQclear(res);
5269
5270         destroyPQExpBuffer(query);
5271
5272         return opcinfo;
5273 }
5274
5275 /*
5276  * getOpfamilies:
5277  *        read all opfamilies in the system catalogs and return them in the
5278  * OpfamilyInfo* structure
5279  *
5280  *      numOpfamilies is set to the number of opfamilies read in
5281  */
5282 OpfamilyInfo *
5283 getOpfamilies(Archive *fout, int *numOpfamilies)
5284 {
5285         PGresult   *res;
5286         int                     ntups;
5287         int                     i;
5288         PQExpBuffer query;
5289         OpfamilyInfo *opfinfo;
5290         int                     i_tableoid;
5291         int                     i_oid;
5292         int                     i_opfname;
5293         int                     i_opfnamespace;
5294         int                     i_rolname;
5295
5296         /* Before 8.3, there is no separate concept of opfamilies */
5297         if (fout->remoteVersion < 80300)
5298         {
5299                 *numOpfamilies = 0;
5300                 return NULL;
5301         }
5302
5303         query = createPQExpBuffer();
5304
5305         /*
5306          * find all opfamilies, including builtin opfamilies; we filter out
5307          * system-defined opfamilies at dump-out time.
5308          */
5309
5310         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5311                                           "opfnamespace, "
5312                                           "(%s opfowner) AS rolname "
5313                                           "FROM pg_opfamily",
5314                                           username_subquery);
5315
5316         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5317
5318         ntups = PQntuples(res);
5319         *numOpfamilies = ntups;
5320
5321         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5322
5323         i_tableoid = PQfnumber(res, "tableoid");
5324         i_oid = PQfnumber(res, "oid");
5325         i_opfname = PQfnumber(res, "opfname");
5326         i_opfnamespace = PQfnumber(res, "opfnamespace");
5327         i_rolname = PQfnumber(res, "rolname");
5328
5329         for (i = 0; i < ntups; i++)
5330         {
5331                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5332                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5333                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5334                 AssignDumpId(&opfinfo[i].dobj);
5335                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5336                 opfinfo[i].dobj.namespace =
5337                         findNamespace(fout,
5338                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5339                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5340
5341                 /* Decide whether we want to dump it */
5342                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5343
5344                 /* Extensions do not currently have ACLs. */
5345                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5346
5347                 if (strlen(opfinfo[i].rolname) == 0)
5348                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5349                                           opfinfo[i].dobj.name);
5350         }
5351
5352         PQclear(res);
5353
5354         destroyPQExpBuffer(query);
5355
5356         return opfinfo;
5357 }
5358
5359 /*
5360  * getAggregates:
5361  *        read all the user-defined aggregates in the system catalogs and
5362  * return them in the AggInfo* structure
5363  *
5364  * numAggs is set to the number of aggregates read in
5365  */
5366 AggInfo *
5367 getAggregates(Archive *fout, int *numAggs)
5368 {
5369         DumpOptions *dopt = fout->dopt;
5370         PGresult   *res;
5371         int                     ntups;
5372         int                     i;
5373         PQExpBuffer query = createPQExpBuffer();
5374         AggInfo    *agginfo;
5375         int                     i_tableoid;
5376         int                     i_oid;
5377         int                     i_aggname;
5378         int                     i_aggnamespace;
5379         int                     i_pronargs;
5380         int                     i_proargtypes;
5381         int                     i_rolname;
5382         int                     i_aggacl;
5383         int                     i_raggacl;
5384         int                     i_initaggacl;
5385         int                     i_initraggacl;
5386
5387         /*
5388          * Find all interesting aggregates.  See comment in getFuncs() for the
5389          * rationale behind the filtering logic.
5390          */
5391         if (fout->remoteVersion >= 90600)
5392         {
5393                 PQExpBuffer acl_subquery = createPQExpBuffer();
5394                 PQExpBuffer racl_subquery = createPQExpBuffer();
5395                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5396                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5397
5398                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5399                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5400                                                 dopt->binary_upgrade);
5401
5402                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5403                                                   "p.proname AS aggname, "
5404                                                   "p.pronamespace AS aggnamespace, "
5405                                                   "p.pronargs, p.proargtypes, "
5406                                                   "(%s p.proowner) AS rolname, "
5407                                                   "%s AS aggacl, "
5408                                                   "%s AS raggacl, "
5409                                                   "%s AS initaggacl, "
5410                                                   "%s AS initraggacl "
5411                                                   "FROM pg_proc p "
5412                                                   "LEFT JOIN pg_init_privs pip ON "
5413                                                   "(p.oid = pip.objoid "
5414                                                   "AND pip.classoid = 'pg_proc'::regclass "
5415                                                   "AND pip.objsubid = 0) "
5416                                                   "WHERE p.proisagg AND ("
5417                                                   "p.pronamespace != "
5418                                                   "(SELECT oid FROM pg_namespace "
5419                                                   "WHERE nspname = 'pg_catalog') OR "
5420                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5421                                                   username_subquery,
5422                                                   acl_subquery->data,
5423                                                   racl_subquery->data,
5424                                                   initacl_subquery->data,
5425                                                   initracl_subquery->data);
5426                 if (dopt->binary_upgrade)
5427                         appendPQExpBufferStr(query,
5428                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5429                                                                  "classid = 'pg_proc'::regclass AND "
5430                                                                  "objid = p.oid AND "
5431                                                                  "refclassid = 'pg_extension'::regclass AND "
5432                                                                  "deptype = 'e')");
5433                 appendPQExpBufferChar(query, ')');
5434
5435                 destroyPQExpBuffer(acl_subquery);
5436                 destroyPQExpBuffer(racl_subquery);
5437                 destroyPQExpBuffer(initacl_subquery);
5438                 destroyPQExpBuffer(initracl_subquery);
5439         }
5440         else if (fout->remoteVersion >= 80200)
5441         {
5442                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5443                                                   "pronamespace AS aggnamespace, "
5444                                                   "pronargs, proargtypes, "
5445                                                   "(%s proowner) AS rolname, "
5446                                                   "proacl AS aggacl, "
5447                                                   "NULL AS raggacl, "
5448                                                   "NULL AS initaggacl, NULL AS initraggacl "
5449                                                   "FROM pg_proc p "
5450                                                   "WHERE proisagg AND ("
5451                                                   "pronamespace != "
5452                                                   "(SELECT oid FROM pg_namespace "
5453                                                   "WHERE nspname = 'pg_catalog')",
5454                                                   username_subquery);
5455                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5456                         appendPQExpBufferStr(query,
5457                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5458                                                                  "classid = 'pg_proc'::regclass AND "
5459                                                                  "objid = p.oid AND "
5460                                                                  "refclassid = 'pg_extension'::regclass AND "
5461                                                                  "deptype = 'e')");
5462                 appendPQExpBufferChar(query, ')');
5463         }
5464         else
5465         {
5466                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5467                                                   "pronamespace AS aggnamespace, "
5468                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5469                                                   "proargtypes, "
5470                                                   "(%s proowner) AS rolname, "
5471                                                   "proacl AS aggacl, "
5472                                                   "NULL AS raggacl, "
5473                                                   "NULL AS initaggacl, NULL AS initraggacl "
5474                                                   "FROM pg_proc "
5475                                                   "WHERE proisagg "
5476                                                   "AND pronamespace != "
5477                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5478                                                   username_subquery);
5479         }
5480
5481         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5482
5483         ntups = PQntuples(res);
5484         *numAggs = ntups;
5485
5486         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5487
5488         i_tableoid = PQfnumber(res, "tableoid");
5489         i_oid = PQfnumber(res, "oid");
5490         i_aggname = PQfnumber(res, "aggname");
5491         i_aggnamespace = PQfnumber(res, "aggnamespace");
5492         i_pronargs = PQfnumber(res, "pronargs");
5493         i_proargtypes = PQfnumber(res, "proargtypes");
5494         i_rolname = PQfnumber(res, "rolname");
5495         i_aggacl = PQfnumber(res, "aggacl");
5496         i_raggacl = PQfnumber(res, "raggacl");
5497         i_initaggacl = PQfnumber(res, "initaggacl");
5498         i_initraggacl = PQfnumber(res, "initraggacl");
5499
5500         for (i = 0; i < ntups; i++)
5501         {
5502                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5503                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5504                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5505                 AssignDumpId(&agginfo[i].aggfn.dobj);
5506                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5507                 agginfo[i].aggfn.dobj.namespace =
5508                         findNamespace(fout,
5509                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5510                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5511                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5512                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5513                                           agginfo[i].aggfn.dobj.name);
5514                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5515                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5516                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5517                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5518                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5519                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5520                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5521                 if (agginfo[i].aggfn.nargs == 0)
5522                         agginfo[i].aggfn.argtypes = NULL;
5523                 else
5524                 {
5525                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5526                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5527                                                   agginfo[i].aggfn.argtypes,
5528                                                   agginfo[i].aggfn.nargs);
5529                 }
5530
5531                 /* Decide whether we want to dump it */
5532                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5533
5534                 /* Do not try to dump ACL if no ACL exists. */
5535                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5536                         PQgetisnull(res, i, i_initaggacl) &&
5537                         PQgetisnull(res, i, i_initraggacl))
5538                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5539         }
5540
5541         PQclear(res);
5542
5543         destroyPQExpBuffer(query);
5544
5545         return agginfo;
5546 }
5547
5548 /*
5549  * getFuncs:
5550  *        read all the user-defined functions in the system catalogs and
5551  * return them in the FuncInfo* structure
5552  *
5553  * numFuncs is set to the number of functions read in
5554  */
5555 FuncInfo *
5556 getFuncs(Archive *fout, int *numFuncs)
5557 {
5558         DumpOptions *dopt = fout->dopt;
5559         PGresult   *res;
5560         int                     ntups;
5561         int                     i;
5562         PQExpBuffer query = createPQExpBuffer();
5563         FuncInfo   *finfo;
5564         int                     i_tableoid;
5565         int                     i_oid;
5566         int                     i_proname;
5567         int                     i_pronamespace;
5568         int                     i_rolname;
5569         int                     i_prolang;
5570         int                     i_pronargs;
5571         int                     i_proargtypes;
5572         int                     i_prorettype;
5573         int                     i_proacl;
5574         int                     i_rproacl;
5575         int                     i_initproacl;
5576         int                     i_initrproacl;
5577
5578         /*
5579          * Find all interesting functions.  This is a bit complicated:
5580          *
5581          * 1. Always exclude aggregates; those are handled elsewhere.
5582          *
5583          * 2. Always exclude functions that are internally dependent on something
5584          * else, since presumably those will be created as a result of creating
5585          * the something else.  This currently acts only to suppress constructor
5586          * functions for range types (so we only need it in 9.2 and up).  Note
5587          * this is OK only because the constructors don't have any dependencies
5588          * the range type doesn't have; otherwise we might not get creation
5589          * ordering correct.
5590          *
5591          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5592          * they're members of extensions and we are in binary-upgrade mode then
5593          * include them, since we want to dump extension members individually in
5594          * that mode.  Also, if they are used by casts or transforms then we need
5595          * to gather the information about them, though they won't be dumped if
5596          * they are built-in.  Also, in 9.6 and up, include functions in
5597          * pg_catalog if they have an ACL different from what's shown in
5598          * pg_init_privs.
5599          */
5600         if (fout->remoteVersion >= 90600)
5601         {
5602                 PQExpBuffer acl_subquery = createPQExpBuffer();
5603                 PQExpBuffer racl_subquery = createPQExpBuffer();
5604                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5605                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5606
5607                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5608                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5609                                                 dopt->binary_upgrade);
5610
5611                 appendPQExpBuffer(query,
5612                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5613                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5614                                                   "%s AS proacl, "
5615                                                   "%s AS rproacl, "
5616                                                   "%s AS initproacl, "
5617                                                   "%s AS initrproacl, "
5618                                                   "p.pronamespace, "
5619                                                   "(%s p.proowner) AS rolname "
5620                                                   "FROM pg_proc p "
5621                                                   "LEFT JOIN pg_init_privs pip ON "
5622                                                   "(p.oid = pip.objoid "
5623                                                   "AND pip.classoid = 'pg_proc'::regclass "
5624                                                   "AND pip.objsubid = 0) "
5625                                                   "WHERE NOT proisagg"
5626                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5627                                                   "WHERE classid = 'pg_proc'::regclass AND "
5628                                                   "objid = p.oid AND deptype = 'i')"
5629                                                   "\n  AND ("
5630                                                   "\n  pronamespace != "
5631                                                   "(SELECT oid FROM pg_namespace "
5632                                                   "WHERE nspname = 'pg_catalog')"
5633                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5634                                                   "\n  WHERE pg_cast.oid > %u "
5635                                                   "\n  AND p.oid = pg_cast.castfunc)"
5636                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5637                                                   "\n  WHERE pg_transform.oid > %u AND "
5638                                                   "\n  (p.oid = pg_transform.trffromsql"
5639                                                   "\n  OR p.oid = pg_transform.trftosql))",
5640                                                   acl_subquery->data,
5641                                                   racl_subquery->data,
5642                                                   initacl_subquery->data,
5643                                                   initracl_subquery->data,
5644                                                   username_subquery,
5645                                                   g_last_builtin_oid,
5646                                                   g_last_builtin_oid);
5647                 if (dopt->binary_upgrade)
5648                         appendPQExpBufferStr(query,
5649                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5650                                                                  "classid = 'pg_proc'::regclass AND "
5651                                                                  "objid = p.oid AND "
5652                                                                  "refclassid = 'pg_extension'::regclass AND "
5653                                                                  "deptype = 'e')");
5654                 appendPQExpBufferStr(query,
5655                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5656                 appendPQExpBufferChar(query, ')');
5657
5658                 destroyPQExpBuffer(acl_subquery);
5659                 destroyPQExpBuffer(racl_subquery);
5660                 destroyPQExpBuffer(initacl_subquery);
5661                 destroyPQExpBuffer(initracl_subquery);
5662         }
5663         else
5664         {
5665                 appendPQExpBuffer(query,
5666                                                   "SELECT tableoid, oid, proname, prolang, "
5667                                                   "pronargs, proargtypes, prorettype, proacl, "
5668                                                   "NULL as rproacl, "
5669                                                   "NULL as initproacl, NULL AS initrproacl, "
5670                                                   "pronamespace, "
5671                                                   "(%s proowner) AS rolname "
5672                                                   "FROM pg_proc p "
5673                                                   "WHERE NOT proisagg",
5674                                                   username_subquery);
5675                 if (fout->remoteVersion >= 90200)
5676                         appendPQExpBufferStr(query,
5677                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5678                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5679                                                                  "objid = p.oid AND deptype = 'i')");
5680                 appendPQExpBuffer(query,
5681                                                   "\n  AND ("
5682                                                   "\n  pronamespace != "
5683                                                   "(SELECT oid FROM pg_namespace "
5684                                                   "WHERE nspname = 'pg_catalog')"
5685                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5686                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5687                                                   "\n  AND p.oid = pg_cast.castfunc)",
5688                                                   g_last_builtin_oid);
5689
5690                 if (fout->remoteVersion >= 90500)
5691                         appendPQExpBuffer(query,
5692                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5693                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5694                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5695                                                           "\n  OR p.oid = pg_transform.trftosql))",
5696                                                           g_last_builtin_oid);
5697
5698                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5699                         appendPQExpBufferStr(query,
5700                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5701                                                                  "classid = 'pg_proc'::regclass AND "
5702                                                                  "objid = p.oid AND "
5703                                                                  "refclassid = 'pg_extension'::regclass AND "
5704                                                                  "deptype = 'e')");
5705                 appendPQExpBufferChar(query, ')');
5706         }
5707
5708         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5709
5710         ntups = PQntuples(res);
5711
5712         *numFuncs = ntups;
5713
5714         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5715
5716         i_tableoid = PQfnumber(res, "tableoid");
5717         i_oid = PQfnumber(res, "oid");
5718         i_proname = PQfnumber(res, "proname");
5719         i_pronamespace = PQfnumber(res, "pronamespace");
5720         i_rolname = PQfnumber(res, "rolname");
5721         i_prolang = PQfnumber(res, "prolang");
5722         i_pronargs = PQfnumber(res, "pronargs");
5723         i_proargtypes = PQfnumber(res, "proargtypes");
5724         i_prorettype = PQfnumber(res, "prorettype");
5725         i_proacl = PQfnumber(res, "proacl");
5726         i_rproacl = PQfnumber(res, "rproacl");
5727         i_initproacl = PQfnumber(res, "initproacl");
5728         i_initrproacl = PQfnumber(res, "initrproacl");
5729
5730         for (i = 0; i < ntups; i++)
5731         {
5732                 finfo[i].dobj.objType = DO_FUNC;
5733                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5734                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5735                 AssignDumpId(&finfo[i].dobj);
5736                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5737                 finfo[i].dobj.namespace =
5738                         findNamespace(fout,
5739                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5740                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5741                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5742                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5743                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5744                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5745                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5746                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5747                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5748                 if (finfo[i].nargs == 0)
5749                         finfo[i].argtypes = NULL;
5750                 else
5751                 {
5752                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5753                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5754                                                   finfo[i].argtypes, finfo[i].nargs);
5755                 }
5756
5757                 /* Decide whether we want to dump it */
5758                 selectDumpableObject(&(finfo[i].dobj), fout);
5759
5760                 /* Do not try to dump ACL if no ACL exists. */
5761                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5762                         PQgetisnull(res, i, i_initproacl) &&
5763                         PQgetisnull(res, i, i_initrproacl))
5764                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5765
5766                 if (strlen(finfo[i].rolname) == 0)
5767                         write_msg(NULL,
5768                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5769                                           finfo[i].dobj.name);
5770         }
5771
5772         PQclear(res);
5773
5774         destroyPQExpBuffer(query);
5775
5776         return finfo;
5777 }
5778
5779 /*
5780  * getTables
5781  *        read all the tables (no indexes)
5782  * in the system catalogs return them in the TableInfo* structure
5783  *
5784  * numTables is set to the number of tables read in
5785  */
5786 TableInfo *
5787 getTables(Archive *fout, int *numTables)
5788 {
5789         DumpOptions *dopt = fout->dopt;
5790         PGresult   *res;
5791         int                     ntups;
5792         int                     i;
5793         PQExpBuffer query = createPQExpBuffer();
5794         TableInfo  *tblinfo;
5795         int                     i_reltableoid;
5796         int                     i_reloid;
5797         int                     i_relname;
5798         int                     i_relnamespace;
5799         int                     i_relkind;
5800         int                     i_relacl;
5801         int                     i_rrelacl;
5802         int                     i_initrelacl;
5803         int                     i_initrrelacl;
5804         int                     i_rolname;
5805         int                     i_relchecks;
5806         int                     i_relhastriggers;
5807         int                     i_relhasindex;
5808         int                     i_relhasrules;
5809         int                     i_relrowsec;
5810         int                     i_relforcerowsec;
5811         int                     i_relhasoids;
5812         int                     i_relfrozenxid;
5813         int                     i_relminmxid;
5814         int                     i_toastoid;
5815         int                     i_toastfrozenxid;
5816         int                     i_toastminmxid;
5817         int                     i_relpersistence;
5818         int                     i_relispopulated;
5819         int                     i_relreplident;
5820         int                     i_owning_tab;
5821         int                     i_owning_col;
5822         int                     i_reltablespace;
5823         int                     i_reloptions;
5824         int                     i_checkoption;
5825         int                     i_toastreloptions;
5826         int                     i_reloftype;
5827         int                     i_relpages;
5828         int                     i_is_identity_sequence;
5829         int                     i_changed_acl;
5830         int                     i_partkeydef;
5831         int                     i_ispartition;
5832         int                     i_partbound;
5833
5834         /*
5835          * Find all the tables and table-like objects.
5836          *
5837          * We include system catalogs, so that we can work if a user table is
5838          * defined to inherit from a system catalog (pretty weird, but...)
5839          *
5840          * We ignore relations that are not ordinary tables, sequences, views,
5841          * materialized views, composite types, or foreign tables.
5842          *
5843          * Composite-type table entries won't be dumped as such, but we have to
5844          * make a DumpableObject for them so that we can track dependencies of the
5845          * composite type (pg_depend entries for columns of the composite type
5846          * link to the pg_class entry not the pg_type entry).
5847          *
5848          * Note: in this phase we should collect only a minimal amount of
5849          * information about each table, basically just enough to decide if it is
5850          * interesting. We must fetch all tables in this phase because otherwise
5851          * we cannot correctly identify inherited columns, owned sequences, etc.
5852          */
5853
5854         if (fout->remoteVersion >= 90600)
5855         {
5856                 char       *partkeydef = "NULL";
5857                 char       *ispartition = "false";
5858                 char       *partbound = "NULL";
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                 /*
5883                  * Left join to pick up dependency info linking sequences to their
5884                  * owning column, if any (note this dependency is AUTO as of 8.2)
5885                  *
5886                  * Left join to detect if any privileges are still as-set-at-init, in
5887                  * which case we won't dump out ACL commands for those.
5888                  */
5889
5890                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5891                                                 initracl_subquery, "c.relacl", "c.relowner",
5892                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5893                                                 " THEN 's' ELSE 'r' END::\"char\"",
5894                                                 dopt->binary_upgrade);
5895
5896                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5897                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5898                                                 dopt->binary_upgrade);
5899
5900                 appendPQExpBuffer(query,
5901                                                   "SELECT c.tableoid, c.oid, c.relname, "
5902                                                   "%s AS relacl, %s as rrelacl, "
5903                                                   "%s AS initrelacl, %s as initrrelacl, "
5904                                                   "c.relkind, c.relnamespace, "
5905                                                   "(%s c.relowner) AS rolname, "
5906                                                   "c.relchecks, c.relhastriggers, "
5907                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
5908                                                   "c.relrowsecurity, c.relforcerowsecurity, "
5909                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5910                                                   "tc.relfrozenxid AS tfrozenxid, "
5911                                                   "tc.relminmxid AS tminmxid, "
5912                                                   "c.relpersistence, c.relispopulated, "
5913                                                   "c.relreplident, c.relpages, "
5914                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5915                                                   "d.refobjid AS owning_tab, "
5916                                                   "d.refobjsubid AS owning_col, "
5917                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5918                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5919                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5920                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5921                                                   "tc.reloptions AS toast_reloptions, "
5922                                                   "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, "
5923                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5924                                                   "(c.oid = pip.objoid "
5925                                                   "AND pip.classoid = 'pg_class'::regclass "
5926                                                   "AND pip.objsubid = at.attnum)"
5927                                                   "WHERE at.attrelid = c.oid AND ("
5928                                                   "%s IS NOT NULL "
5929                                                   "OR %s IS NOT NULL "
5930                                                   "OR %s IS NOT NULL "
5931                                                   "OR %s IS NOT NULL"
5932                                                   "))"
5933                                                   "AS changed_acl, "
5934                                                   "%s AS partkeydef, "
5935                                                   "%s AS ispartition, "
5936                                                   "%s AS partbound "
5937                                                   "FROM pg_class c "
5938                                                   "LEFT JOIN pg_depend d ON "
5939                                                   "(c.relkind = '%c' AND "
5940                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
5941                                                   "d.objsubid = 0 AND "
5942                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
5943                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5944                                                   "LEFT JOIN pg_init_privs pip ON "
5945                                                   "(c.oid = pip.objoid "
5946                                                   "AND pip.classoid = 'pg_class'::regclass "
5947                                                   "AND pip.objsubid = 0) "
5948                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
5949                                                   "ORDER BY c.oid",
5950                                                   acl_subquery->data,
5951                                                   racl_subquery->data,
5952                                                   initacl_subquery->data,
5953                                                   initracl_subquery->data,
5954                                                   username_subquery,
5955                                                   RELKIND_SEQUENCE,
5956                                                   attacl_subquery->data,
5957                                                   attracl_subquery->data,
5958                                                   attinitacl_subquery->data,
5959                                                   attinitracl_subquery->data,
5960                                                   partkeydef,
5961                                                   ispartition,
5962                                                   partbound,
5963                                                   RELKIND_SEQUENCE,
5964                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
5965                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5966                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
5967                                                   RELKIND_PARTITIONED_TABLE);
5968
5969                 destroyPQExpBuffer(acl_subquery);
5970                 destroyPQExpBuffer(racl_subquery);
5971                 destroyPQExpBuffer(initacl_subquery);
5972                 destroyPQExpBuffer(initracl_subquery);
5973
5974                 destroyPQExpBuffer(attacl_subquery);
5975                 destroyPQExpBuffer(attracl_subquery);
5976                 destroyPQExpBuffer(attinitacl_subquery);
5977                 destroyPQExpBuffer(attinitracl_subquery);
5978         }
5979         else if (fout->remoteVersion >= 90500)
5980         {
5981                 /*
5982                  * Left join to pick up dependency info linking sequences to their
5983                  * owning column, if any (note this dependency is AUTO as of 8.2)
5984                  */
5985                 appendPQExpBuffer(query,
5986                                                   "SELECT c.tableoid, c.oid, c.relname, "
5987                                                   "c.relacl, NULL as rrelacl, "
5988                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
5989                                                   "c.relkind, "
5990                                                   "c.relnamespace, "
5991                                                   "(%s c.relowner) AS rolname, "
5992                                                   "c.relchecks, c.relhastriggers, "
5993                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
5994                                                   "c.relrowsecurity, c.relforcerowsecurity, "
5995                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5996                                                   "tc.relfrozenxid AS tfrozenxid, "
5997                                                   "tc.relminmxid AS tminmxid, "
5998                                                   "c.relpersistence, c.relispopulated, "
5999                                                   "c.relreplident, c.relpages, "
6000                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6001                                                   "d.refobjid AS owning_tab, "
6002                                                   "d.refobjsubid AS owning_col, "
6003                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6004                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6005                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6006                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6007                                                   "tc.reloptions AS toast_reloptions, "
6008                                                   "NULL AS changed_acl, "
6009                                                   "NULL AS partkeydef, "
6010                                                   "false AS ispartition, "
6011                                                   "NULL AS partbound "
6012                                                   "FROM pg_class c "
6013                                                   "LEFT JOIN pg_depend d ON "
6014                                                   "(c.relkind = '%c' AND "
6015                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6016                                                   "d.objsubid = 0 AND "
6017                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6018                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6019                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6020                                                   "ORDER BY c.oid",
6021                                                   username_subquery,
6022                                                   RELKIND_SEQUENCE,
6023                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6024                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6025                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6026         }
6027         else if (fout->remoteVersion >= 90400)
6028         {
6029                 /*
6030                  * Left join to pick up dependency info linking sequences to their
6031                  * owning column, if any (note this dependency is AUTO as of 8.2)
6032                  */
6033                 appendPQExpBuffer(query,
6034                                                   "SELECT c.tableoid, c.oid, c.relname, "
6035                                                   "c.relacl, NULL as rrelacl, "
6036                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6037                                                   "c.relkind, "
6038                                                   "c.relnamespace, "
6039                                                   "(%s c.relowner) AS rolname, "
6040                                                   "c.relchecks, c.relhastriggers, "
6041                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6042                                                   "'f'::bool AS relrowsecurity, "
6043                                                   "'f'::bool AS relforcerowsecurity, "
6044                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6045                                                   "tc.relfrozenxid AS tfrozenxid, "
6046                                                   "tc.relminmxid AS tminmxid, "
6047                                                   "c.relpersistence, c.relispopulated, "
6048                                                   "c.relreplident, c.relpages, "
6049                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6050                                                   "d.refobjid AS owning_tab, "
6051                                                   "d.refobjsubid AS owning_col, "
6052                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6053                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6054                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6055                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6056                                                   "tc.reloptions AS toast_reloptions, "
6057                                                   "NULL AS changed_acl, "
6058                                                   "NULL AS partkeydef, "
6059                                                   "false AS ispartition, "
6060                                                   "NULL AS partbound "
6061                                                   "FROM pg_class c "
6062                                                   "LEFT JOIN pg_depend d ON "
6063                                                   "(c.relkind = '%c' AND "
6064                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6065                                                   "d.objsubid = 0 AND "
6066                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6067                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6068                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6069                                                   "ORDER BY c.oid",
6070                                                   username_subquery,
6071                                                   RELKIND_SEQUENCE,
6072                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6073                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6074                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6075         }
6076         else if (fout->remoteVersion >= 90300)
6077         {
6078                 /*
6079                  * Left join to pick up dependency info linking sequences to their
6080                  * owning column, if any (note this dependency is AUTO as of 8.2)
6081                  */
6082                 appendPQExpBuffer(query,
6083                                                   "SELECT c.tableoid, c.oid, c.relname, "
6084                                                   "c.relacl, NULL as rrelacl, "
6085                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6086                                                   "c.relkind, "
6087                                                   "c.relnamespace, "
6088                                                   "(%s c.relowner) AS rolname, "
6089                                                   "c.relchecks, c.relhastriggers, "
6090                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6091                                                   "'f'::bool AS relrowsecurity, "
6092                                                   "'f'::bool AS relforcerowsecurity, "
6093                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6094                                                   "tc.relfrozenxid AS tfrozenxid, "
6095                                                   "tc.relminmxid AS tminmxid, "
6096                                                   "c.relpersistence, c.relispopulated, "
6097                                                   "'d' AS relreplident, c.relpages, "
6098                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6099                                                   "d.refobjid AS owning_tab, "
6100                                                   "d.refobjsubid AS owning_col, "
6101                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6102                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6103                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6104                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6105                                                   "tc.reloptions AS toast_reloptions, "
6106                                                   "NULL AS changed_acl, "
6107                                                   "NULL AS partkeydef, "
6108                                                   "false AS ispartition, "
6109                                                   "NULL AS partbound "
6110                                                   "FROM pg_class c "
6111                                                   "LEFT JOIN pg_depend d ON "
6112                                                   "(c.relkind = '%c' AND "
6113                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6114                                                   "d.objsubid = 0 AND "
6115                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6116                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6117                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6118                                                   "ORDER BY c.oid",
6119                                                   username_subquery,
6120                                                   RELKIND_SEQUENCE,
6121                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6122                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6123                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6124         }
6125         else if (fout->remoteVersion >= 90100)
6126         {
6127                 /*
6128                  * Left join to pick up dependency info linking sequences to their
6129                  * owning column, if any (note this dependency is AUTO as of 8.2)
6130                  */
6131                 appendPQExpBuffer(query,
6132                                                   "SELECT c.tableoid, c.oid, c.relname, "
6133                                                   "c.relacl, NULL as rrelacl, "
6134                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6135                                                   "c.relkind, "
6136                                                   "c.relnamespace, "
6137                                                   "(%s c.relowner) AS rolname, "
6138                                                   "c.relchecks, c.relhastriggers, "
6139                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6140                                                   "'f'::bool AS relrowsecurity, "
6141                                                   "'f'::bool AS relforcerowsecurity, "
6142                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6143                                                   "tc.relfrozenxid AS tfrozenxid, "
6144                                                   "0 AS tminmxid, "
6145                                                   "c.relpersistence, 't' as relispopulated, "
6146                                                   "'d' AS relreplident, c.relpages, "
6147                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6148                                                   "d.refobjid AS owning_tab, "
6149                                                   "d.refobjsubid AS owning_col, "
6150                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6151                                                   "c.reloptions AS reloptions, "
6152                                                   "tc.reloptions AS toast_reloptions, "
6153                                                   "NULL AS changed_acl, "
6154                                                   "NULL AS partkeydef, "
6155                                                   "false AS ispartition, "
6156                                                   "NULL AS partbound "
6157                                                   "FROM pg_class c "
6158                                                   "LEFT JOIN pg_depend d ON "
6159                                                   "(c.relkind = '%c' AND "
6160                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6161                                                   "d.objsubid = 0 AND "
6162                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6163                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6164                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6165                                                   "ORDER BY c.oid",
6166                                                   username_subquery,
6167                                                   RELKIND_SEQUENCE,
6168                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6169                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6170                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6171         }
6172         else if (fout->remoteVersion >= 90000)
6173         {
6174                 /*
6175                  * Left join to pick up dependency info linking sequences to their
6176                  * owning column, if any (note this dependency is AUTO as of 8.2)
6177                  */
6178                 appendPQExpBuffer(query,
6179                                                   "SELECT c.tableoid, c.oid, c.relname, "
6180                                                   "c.relacl, NULL as rrelacl, "
6181                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6182                                                   "c.relkind, "
6183                                                   "c.relnamespace, "
6184                                                   "(%s c.relowner) AS rolname, "
6185                                                   "c.relchecks, c.relhastriggers, "
6186                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6187                                                   "'f'::bool AS relrowsecurity, "
6188                                                   "'f'::bool AS relforcerowsecurity, "
6189                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6190                                                   "tc.relfrozenxid AS tfrozenxid, "
6191                                                   "0 AS tminmxid, "
6192                                                   "'p' AS relpersistence, 't' as relispopulated, "
6193                                                   "'d' AS relreplident, c.relpages, "
6194                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6195                                                   "d.refobjid AS owning_tab, "
6196                                                   "d.refobjsubid AS owning_col, "
6197                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6198                                                   "c.reloptions AS reloptions, "
6199                                                   "tc.reloptions AS toast_reloptions, "
6200                                                   "NULL AS changed_acl, "
6201                                                   "NULL AS partkeydef, "
6202                                                   "false AS ispartition, "
6203                                                   "NULL AS partbound "
6204                                                   "FROM pg_class c "
6205                                                   "LEFT JOIN pg_depend d ON "
6206                                                   "(c.relkind = '%c' AND "
6207                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6208                                                   "d.objsubid = 0 AND "
6209                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6210                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6211                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6212                                                   "ORDER BY c.oid",
6213                                                   username_subquery,
6214                                                   RELKIND_SEQUENCE,
6215                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6216                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6217         }
6218         else if (fout->remoteVersion >= 80400)
6219         {
6220                 /*
6221                  * Left join to pick up dependency info linking sequences to their
6222                  * owning column, if any (note this dependency is AUTO as of 8.2)
6223                  */
6224                 appendPQExpBuffer(query,
6225                                                   "SELECT c.tableoid, c.oid, c.relname, "
6226                                                   "c.relacl, NULL as rrelacl, "
6227                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6228                                                   "c.relkind, "
6229                                                   "c.relnamespace, "
6230                                                   "(%s c.relowner) AS rolname, "
6231                                                   "c.relchecks, c.relhastriggers, "
6232                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6233                                                   "'f'::bool AS relrowsecurity, "
6234                                                   "'f'::bool AS relforcerowsecurity, "
6235                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6236                                                   "tc.relfrozenxid AS tfrozenxid, "
6237                                                   "0 AS tminmxid, "
6238                                                   "'p' AS relpersistence, 't' as relispopulated, "
6239                                                   "'d' AS relreplident, c.relpages, "
6240                                                   "NULL AS reloftype, "
6241                                                   "d.refobjid AS owning_tab, "
6242                                                   "d.refobjsubid AS owning_col, "
6243                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6244                                                   "c.reloptions AS reloptions, "
6245                                                   "tc.reloptions AS toast_reloptions, "
6246                                                   "NULL AS changed_acl, "
6247                                                   "NULL AS partkeydef, "
6248                                                   "false AS ispartition, "
6249                                                   "NULL AS partbound "
6250                                                   "FROM pg_class c "
6251                                                   "LEFT JOIN pg_depend d ON "
6252                                                   "(c.relkind = '%c' AND "
6253                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6254                                                   "d.objsubid = 0 AND "
6255                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6256                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6257                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6258                                                   "ORDER BY c.oid",
6259                                                   username_subquery,
6260                                                   RELKIND_SEQUENCE,
6261                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6262                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6263         }
6264         else if (fout->remoteVersion >= 80200)
6265         {
6266                 /*
6267                  * Left join to pick up dependency info linking sequences to their
6268                  * owning column, if any (note this dependency is AUTO as of 8.2)
6269                  */
6270                 appendPQExpBuffer(query,
6271                                                   "SELECT c.tableoid, c.oid, c.relname, "
6272                                                   "c.relacl, NULL as rrelacl, "
6273                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6274                                                   "c.relkind, "
6275                                                   "c.relnamespace, "
6276                                                   "(%s c.relowner) AS rolname, "
6277                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6278                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6279                                                   "'f'::bool AS relrowsecurity, "
6280                                                   "'f'::bool AS relforcerowsecurity, "
6281                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6282                                                   "tc.relfrozenxid AS tfrozenxid, "
6283                                                   "0 AS tminmxid, "
6284                                                   "'p' AS relpersistence, 't' as relispopulated, "
6285                                                   "'d' AS relreplident, c.relpages, "
6286                                                   "NULL AS reloftype, "
6287                                                   "d.refobjid AS owning_tab, "
6288                                                   "d.refobjsubid AS owning_col, "
6289                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6290                                                   "c.reloptions AS reloptions, "
6291                                                   "NULL AS toast_reloptions, "
6292                                                   "NULL AS changed_acl, "
6293                                                   "NULL AS partkeydef, "
6294                                                   "false AS ispartition, "
6295                                                   "NULL AS partbound "
6296                                                   "FROM pg_class c "
6297                                                   "LEFT JOIN pg_depend d ON "
6298                                                   "(c.relkind = '%c' AND "
6299                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6300                                                   "d.objsubid = 0 AND "
6301                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6302                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6303                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6304                                                   "ORDER BY c.oid",
6305                                                   username_subquery,
6306                                                   RELKIND_SEQUENCE,
6307                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6308                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6309         }
6310         else
6311         {
6312                 /*
6313                  * Left join to pick up dependency info linking sequences to their
6314                  * owning column, if any
6315                  */
6316                 appendPQExpBuffer(query,
6317                                                   "SELECT c.tableoid, c.oid, relname, "
6318                                                   "relacl, NULL as rrelacl, "
6319                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6320                                                   "relkind, relnamespace, "
6321                                                   "(%s relowner) AS rolname, "
6322                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6323                                                   "relhasindex, relhasrules, relhasoids, "
6324                                                   "'f'::bool AS relrowsecurity, "
6325                                                   "'f'::bool AS relforcerowsecurity, "
6326                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6327                                                   "0 AS toid, "
6328                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6329                                                   "'p' AS relpersistence, 't' as relispopulated, "
6330                                                   "'d' AS relreplident, relpages, "
6331                                                   "NULL AS reloftype, "
6332                                                   "d.refobjid AS owning_tab, "
6333                                                   "d.refobjsubid AS owning_col, "
6334                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6335                                                   "NULL AS reloptions, "
6336                                                   "NULL AS toast_reloptions, "
6337                                                   "NULL AS changed_acl, "
6338                                                   "NULL AS partkeydef, "
6339                                                   "false AS ispartition, "
6340                                                   "NULL AS partbound "
6341                                                   "FROM pg_class c "
6342                                                   "LEFT JOIN pg_depend d ON "
6343                                                   "(c.relkind = '%c' AND "
6344                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6345                                                   "d.objsubid = 0 AND "
6346                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6347                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6348                                                   "ORDER BY c.oid",
6349                                                   username_subquery,
6350                                                   RELKIND_SEQUENCE,
6351                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6352                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6353         }
6354
6355         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6356
6357         ntups = PQntuples(res);
6358
6359         *numTables = ntups;
6360
6361         /*
6362          * Extract data from result and lock dumpable tables.  We do the locking
6363          * before anything else, to minimize the window wherein a table could
6364          * disappear under us.
6365          *
6366          * Note that we have to save info about all tables here, even when dumping
6367          * only one, because we don't yet know which tables might be inheritance
6368          * ancestors of the target table.
6369          */
6370         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6371
6372         i_reltableoid = PQfnumber(res, "tableoid");
6373         i_reloid = PQfnumber(res, "oid");
6374         i_relname = PQfnumber(res, "relname");
6375         i_relnamespace = PQfnumber(res, "relnamespace");
6376         i_relacl = PQfnumber(res, "relacl");
6377         i_rrelacl = PQfnumber(res, "rrelacl");
6378         i_initrelacl = PQfnumber(res, "initrelacl");
6379         i_initrrelacl = PQfnumber(res, "initrrelacl");
6380         i_relkind = PQfnumber(res, "relkind");
6381         i_rolname = PQfnumber(res, "rolname");
6382         i_relchecks = PQfnumber(res, "relchecks");
6383         i_relhastriggers = PQfnumber(res, "relhastriggers");
6384         i_relhasindex = PQfnumber(res, "relhasindex");
6385         i_relhasrules = PQfnumber(res, "relhasrules");
6386         i_relrowsec = PQfnumber(res, "relrowsecurity");
6387         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6388         i_relhasoids = PQfnumber(res, "relhasoids");
6389         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6390         i_relminmxid = PQfnumber(res, "relminmxid");
6391         i_toastoid = PQfnumber(res, "toid");
6392         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6393         i_toastminmxid = PQfnumber(res, "tminmxid");
6394         i_relpersistence = PQfnumber(res, "relpersistence");
6395         i_relispopulated = PQfnumber(res, "relispopulated");
6396         i_relreplident = PQfnumber(res, "relreplident");
6397         i_relpages = PQfnumber(res, "relpages");
6398         i_owning_tab = PQfnumber(res, "owning_tab");
6399         i_owning_col = PQfnumber(res, "owning_col");
6400         i_reltablespace = PQfnumber(res, "reltablespace");
6401         i_reloptions = PQfnumber(res, "reloptions");
6402         i_checkoption = PQfnumber(res, "checkoption");
6403         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6404         i_reloftype = PQfnumber(res, "reloftype");
6405         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6406         i_changed_acl = PQfnumber(res, "changed_acl");
6407         i_partkeydef = PQfnumber(res, "partkeydef");
6408         i_ispartition = PQfnumber(res, "ispartition");
6409         i_partbound = PQfnumber(res, "partbound");
6410
6411         if (dopt->lockWaitTimeout)
6412         {
6413                 /*
6414                  * Arrange to fail instead of waiting forever for a table lock.
6415                  *
6416                  * NB: this coding assumes that the only queries issued within the
6417                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6418                  * applied to other things too.
6419                  */
6420                 resetPQExpBuffer(query);
6421                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6422                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6423                 ExecuteSqlStatement(fout, query->data);
6424         }
6425
6426         for (i = 0; i < ntups; i++)
6427         {
6428                 tblinfo[i].dobj.objType = DO_TABLE;
6429                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6430                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6431                 AssignDumpId(&tblinfo[i].dobj);
6432                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6433                 tblinfo[i].dobj.namespace =
6434                         findNamespace(fout,
6435                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6436                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6437                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6438                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6439                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6440                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6441                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6442                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6443                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6444                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6445                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6446                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6447                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6448                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6449                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6450                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6451                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6452                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6453                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6454                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6455                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6456                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6457                 if (PQgetisnull(res, i, i_reloftype))
6458                         tblinfo[i].reloftype = NULL;
6459                 else
6460                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6461                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6462                 if (PQgetisnull(res, i, i_owning_tab))
6463                 {
6464                         tblinfo[i].owning_tab = InvalidOid;
6465                         tblinfo[i].owning_col = 0;
6466                 }
6467                 else
6468                 {
6469                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6470                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6471                 }
6472                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6473                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6474                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6475                         tblinfo[i].checkoption = NULL;
6476                 else
6477                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6478                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6479
6480                 /* other fields were zeroed above */
6481
6482                 /*
6483                  * Decide whether we want to dump this table.
6484                  */
6485                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6486                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6487                 else
6488                         selectDumpableTable(&tblinfo[i], fout);
6489
6490                 /*
6491                  * If the table-level and all column-level ACLs for this table are
6492                  * unchanged, then we don't need to worry about including the ACLs for
6493                  * this table.  If any column-level ACLs have been changed, the
6494                  * 'changed_acl' column from the query will indicate that.
6495                  *
6496                  * This can result in a significant performance improvement in cases
6497                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6498                  */
6499                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6500                         PQgetisnull(res, i, i_initrelacl) &&
6501                         PQgetisnull(res, i, i_initrrelacl) &&
6502                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6503                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6504
6505                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6506                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6507                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6508
6509                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6510                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6511
6512                 /* Partition key string or NULL */
6513                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6514                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6515                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6516
6517                 /*
6518                  * Read-lock target tables to make sure they aren't DROPPED or altered
6519                  * in schema before we get around to dumping them.
6520                  *
6521                  * Note that we don't explicitly lock parents of the target tables; we
6522                  * assume our lock on the child is enough to prevent schema
6523                  * alterations to parent tables.
6524                  *
6525                  * NOTE: it'd be kinda nice to lock other relations too, not only
6526                  * plain or partitioned tables, but the backend doesn't presently
6527                  * allow that.
6528                  *
6529                  * We only need to lock the table for certain components; see
6530                  * pg_dump.h
6531                  */
6532                 if (tblinfo[i].dobj.dump &&
6533                         (tblinfo[i].relkind == RELKIND_RELATION ||
6534                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6535                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6536                 {
6537                         resetPQExpBuffer(query);
6538                         appendPQExpBuffer(query,
6539                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6540                                                           fmtQualifiedDumpable(&tblinfo[i]));
6541                         ExecuteSqlStatement(fout, query->data);
6542                 }
6543
6544                 /* Emit notice if join for owner failed */
6545                 if (strlen(tblinfo[i].rolname) == 0)
6546                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6547                                           tblinfo[i].dobj.name);
6548         }
6549
6550         if (dopt->lockWaitTimeout)
6551         {
6552                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6553         }
6554
6555         PQclear(res);
6556
6557         destroyPQExpBuffer(query);
6558
6559         return tblinfo;
6560 }
6561
6562 /*
6563  * getOwnedSeqs
6564  *        identify owned sequences and mark them as dumpable if owning table is
6565  *
6566  * We used to do this in getTables(), but it's better to do it after the
6567  * index used by findTableByOid() has been set up.
6568  */
6569 void
6570 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6571 {
6572         int                     i;
6573
6574         /*
6575          * Force sequences that are "owned" by table columns to be dumped whenever
6576          * their owning table is being dumped.
6577          */
6578         for (i = 0; i < numTables; i++)
6579         {
6580                 TableInfo  *seqinfo = &tblinfo[i];
6581                 TableInfo  *owning_tab;
6582
6583                 if (!OidIsValid(seqinfo->owning_tab))
6584                         continue;                       /* not an owned sequence */
6585
6586                 owning_tab = findTableByOid(seqinfo->owning_tab);
6587                 if (owning_tab == NULL)
6588                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6589                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6590
6591                 /*
6592                  * We need to dump the components that are being dumped for the table
6593                  * and any components which the sequence is explicitly marked with.
6594                  *
6595                  * We can't simply use the set of components which are being dumped
6596                  * for the table as the table might be in an extension (and only the
6597                  * non-extension components, eg: ACLs if changed, security labels, and
6598                  * policies, are being dumped) while the sequence is not (and
6599                  * therefore the definition and other components should also be
6600                  * dumped).
6601                  *
6602                  * If the sequence is part of the extension then it should be properly
6603                  * marked by checkExtensionMembership() and this will be a no-op as
6604                  * the table will be equivalently marked.
6605                  */
6606                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6607
6608                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6609                         seqinfo->interesting = true;
6610         }
6611 }
6612
6613 /*
6614  * getInherits
6615  *        read all the inheritance information
6616  * from the system catalogs return them in the InhInfo* structure
6617  *
6618  * numInherits is set to the number of pairs read in
6619  */
6620 InhInfo *
6621 getInherits(Archive *fout, int *numInherits)
6622 {
6623         PGresult   *res;
6624         int                     ntups;
6625         int                     i;
6626         PQExpBuffer query = createPQExpBuffer();
6627         InhInfo    *inhinfo;
6628
6629         int                     i_inhrelid;
6630         int                     i_inhparent;
6631
6632         /*
6633          * Find all the inheritance information, excluding implicit inheritance
6634          * via partitioning.  We handle that case using getPartitions(), because
6635          * we want more information about partitions than just the parent-child
6636          * relationship.
6637          */
6638         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6639
6640         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6641
6642         ntups = PQntuples(res);
6643
6644         *numInherits = ntups;
6645
6646         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6647
6648         i_inhrelid = PQfnumber(res, "inhrelid");
6649         i_inhparent = PQfnumber(res, "inhparent");
6650
6651         for (i = 0; i < ntups; i++)
6652         {
6653                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6654                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6655         }
6656
6657         PQclear(res);
6658
6659         destroyPQExpBuffer(query);
6660
6661         return inhinfo;
6662 }
6663
6664 /*
6665  * getIndexes
6666  *        get information about every index on a dumpable table
6667  *
6668  * Note: index data is not returned directly to the caller, but it
6669  * does get entered into the DumpableObject tables.
6670  */
6671 void
6672 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6673 {
6674         int                     i,
6675                                 j;
6676         PQExpBuffer query = createPQExpBuffer();
6677         PGresult   *res;
6678         IndxInfo   *indxinfo;
6679         ConstraintInfo *constrinfo;
6680         int                     i_tableoid,
6681                                 i_oid,
6682                                 i_indexname,
6683                                 i_parentidx,
6684                                 i_indexdef,
6685                                 i_indnkeys,
6686                                 i_indkey,
6687                                 i_indisclustered,
6688                                 i_indisreplident,
6689                                 i_contype,
6690                                 i_conname,
6691                                 i_condeferrable,
6692                                 i_condeferred,
6693                                 i_contableoid,
6694                                 i_conoid,
6695                                 i_condef,
6696                                 i_tablespace,
6697                                 i_indreloptions,
6698                                 i_relpages;
6699         int                     ntups;
6700
6701         for (i = 0; i < numTables; i++)
6702         {
6703                 TableInfo  *tbinfo = &tblinfo[i];
6704
6705                 if (!tbinfo->hasindex)
6706                         continue;
6707
6708                 /*
6709                  * Ignore indexes of tables whose definitions are not to be dumped.
6710                  *
6711                  * We also need indexes on partitioned tables which have partitions to
6712                  * be dumped, in order to dump the indexes on the partitions.
6713                  */
6714                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6715                         !tbinfo->interesting)
6716                         continue;
6717
6718                 if (g_verbose)
6719                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6720                                           tbinfo->dobj.namespace->dobj.name,
6721                                           tbinfo->dobj.name);
6722
6723                 /*
6724                  * The point of the messy-looking outer join is to find a constraint
6725                  * that is related by an internal dependency link to the index. If we
6726                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6727                  * assume an index won't have more than one internal dependency.
6728                  *
6729                  * As of 9.0 we don't need to look at pg_depend but can check for a
6730                  * match to pg_constraint.conindid.  The check on conrelid is
6731                  * redundant but useful because that column is indexed while conindid
6732                  * is not.
6733                  */
6734                 resetPQExpBuffer(query);
6735                 if (fout->remoteVersion >= 110000)
6736                 {
6737                         appendPQExpBuffer(query,
6738                                                           "SELECT t.tableoid, t.oid, "
6739                                                           "t.relname AS indexname, "
6740                                                           "inh.inhparent AS parentidx, "
6741                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6742                                                           "t.relnatts AS indnkeys, "
6743                                                           "i.indkey, i.indisclustered, "
6744                                                           "i.indisreplident, t.relpages, "
6745                                                           "c.contype, c.conname, "
6746                                                           "c.condeferrable, c.condeferred, "
6747                                                           "c.tableoid AS contableoid, "
6748                                                           "c.oid AS conoid, "
6749                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6750                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6751                                                           "t.reloptions AS indreloptions "
6752                                                           "FROM pg_catalog.pg_index i "
6753                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6754                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6755                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6756                                                           "ON (i.indrelid = c.conrelid AND "
6757                                                           "i.indexrelid = c.conindid AND "
6758                                                           "c.contype IN ('p','u','x')) "
6759                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6760                                                           "ON (inh.inhrelid = indexrelid) "
6761                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6762                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6763                                                           "AND i.indisready "
6764                                                           "ORDER BY indexname",
6765                                                           tbinfo->dobj.catId.oid);
6766                 }
6767                 else if (fout->remoteVersion >= 90400)
6768                 {
6769                         /*
6770                          * the test on indisready is necessary in 9.2, and harmless in
6771                          * earlier/later versions
6772                          */
6773                         appendPQExpBuffer(query,
6774                                                           "SELECT t.tableoid, t.oid, "
6775                                                           "t.relname AS indexname, "
6776                                                           "0 AS parentidx, "
6777                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6778                                                           "t.relnatts AS indnkeys, "
6779                                                           "i.indkey, i.indisclustered, "
6780                                                           "i.indisreplident, t.relpages, "
6781                                                           "c.contype, c.conname, "
6782                                                           "c.condeferrable, c.condeferred, "
6783                                                           "c.tableoid AS contableoid, "
6784                                                           "c.oid AS conoid, "
6785                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6786                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6787                                                           "t.reloptions AS indreloptions "
6788                                                           "FROM pg_catalog.pg_index i "
6789                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6790                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6791                                                           "ON (i.indrelid = c.conrelid AND "
6792                                                           "i.indexrelid = c.conindid AND "
6793                                                           "c.contype IN ('p','u','x')) "
6794                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6795                                                           "AND i.indisvalid AND i.indisready "
6796                                                           "ORDER BY indexname",
6797                                                           tbinfo->dobj.catId.oid);
6798                 }
6799                 else if (fout->remoteVersion >= 90000)
6800                 {
6801                         /*
6802                          * the test on indisready is necessary in 9.2, and harmless in
6803                          * earlier/later versions
6804                          */
6805                         appendPQExpBuffer(query,
6806                                                           "SELECT t.tableoid, t.oid, "
6807                                                           "t.relname AS indexname, "
6808                                                           "0 AS parentidx, "
6809                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6810                                                           "t.relnatts AS indnkeys, "
6811                                                           "i.indkey, i.indisclustered, "
6812                                                           "false AS indisreplident, t.relpages, "
6813                                                           "c.contype, c.conname, "
6814                                                           "c.condeferrable, c.condeferred, "
6815                                                           "c.tableoid AS contableoid, "
6816                                                           "c.oid AS conoid, "
6817                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6818                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6819                                                           "t.reloptions AS indreloptions "
6820                                                           "FROM pg_catalog.pg_index i "
6821                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6822                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6823                                                           "ON (i.indrelid = c.conrelid AND "
6824                                                           "i.indexrelid = c.conindid AND "
6825                                                           "c.contype IN ('p','u','x')) "
6826                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6827                                                           "AND i.indisvalid AND i.indisready "
6828                                                           "ORDER BY indexname",
6829                                                           tbinfo->dobj.catId.oid);
6830                 }
6831                 else if (fout->remoteVersion >= 80200)
6832                 {
6833                         appendPQExpBuffer(query,
6834                                                           "SELECT t.tableoid, t.oid, "
6835                                                           "t.relname AS indexname, "
6836                                                           "0 AS parentidx, "
6837                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6838                                                           "t.relnatts AS indnkeys, "
6839                                                           "i.indkey, i.indisclustered, "
6840                                                           "false AS indisreplident, t.relpages, "
6841                                                           "c.contype, c.conname, "
6842                                                           "c.condeferrable, c.condeferred, "
6843                                                           "c.tableoid AS contableoid, "
6844                                                           "c.oid AS conoid, "
6845                                                           "null AS condef, "
6846                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6847                                                           "t.reloptions AS indreloptions "
6848                                                           "FROM pg_catalog.pg_index i "
6849                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6850                                                           "LEFT JOIN pg_catalog.pg_depend d "
6851                                                           "ON (d.classid = t.tableoid "
6852                                                           "AND d.objid = t.oid "
6853                                                           "AND d.deptype = 'i') "
6854                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6855                                                           "ON (d.refclassid = c.tableoid "
6856                                                           "AND d.refobjid = c.oid) "
6857                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6858                                                           "AND i.indisvalid "
6859                                                           "ORDER BY indexname",
6860                                                           tbinfo->dobj.catId.oid);
6861                 }
6862                 else
6863                 {
6864                         appendPQExpBuffer(query,
6865                                                           "SELECT t.tableoid, t.oid, "
6866                                                           "t.relname AS indexname, "
6867                                                           "0 AS parentidx, "
6868                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6869                                                           "t.relnatts AS indnkeys, "
6870                                                           "i.indkey, i.indisclustered, "
6871                                                           "false AS indisreplident, t.relpages, "
6872                                                           "c.contype, c.conname, "
6873                                                           "c.condeferrable, c.condeferred, "
6874                                                           "c.tableoid AS contableoid, "
6875                                                           "c.oid AS conoid, "
6876                                                           "null AS condef, "
6877                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6878                                                           "null AS indreloptions "
6879                                                           "FROM pg_catalog.pg_index i "
6880                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6881                                                           "LEFT JOIN pg_catalog.pg_depend d "
6882                                                           "ON (d.classid = t.tableoid "
6883                                                           "AND d.objid = t.oid "
6884                                                           "AND d.deptype = 'i') "
6885                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6886                                                           "ON (d.refclassid = c.tableoid "
6887                                                           "AND d.refobjid = c.oid) "
6888                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6889                                                           "ORDER BY indexname",
6890                                                           tbinfo->dobj.catId.oid);
6891                 }
6892
6893                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6894
6895                 ntups = PQntuples(res);
6896
6897                 i_tableoid = PQfnumber(res, "tableoid");
6898                 i_oid = PQfnumber(res, "oid");
6899                 i_indexname = PQfnumber(res, "indexname");
6900                 i_parentidx = PQfnumber(res, "parentidx");
6901                 i_indexdef = PQfnumber(res, "indexdef");
6902                 i_indnkeys = PQfnumber(res, "indnkeys");
6903                 i_indkey = PQfnumber(res, "indkey");
6904                 i_indisclustered = PQfnumber(res, "indisclustered");
6905                 i_indisreplident = PQfnumber(res, "indisreplident");
6906                 i_relpages = PQfnumber(res, "relpages");
6907                 i_contype = PQfnumber(res, "contype");
6908                 i_conname = PQfnumber(res, "conname");
6909                 i_condeferrable = PQfnumber(res, "condeferrable");
6910                 i_condeferred = PQfnumber(res, "condeferred");
6911                 i_contableoid = PQfnumber(res, "contableoid");
6912                 i_conoid = PQfnumber(res, "conoid");
6913                 i_condef = PQfnumber(res, "condef");
6914                 i_tablespace = PQfnumber(res, "tablespace");
6915                 i_indreloptions = PQfnumber(res, "indreloptions");
6916
6917                 tbinfo->indexes = indxinfo =
6918                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
6919                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6920                 tbinfo->numIndexes = ntups;
6921
6922                 for (j = 0; j < ntups; j++)
6923                 {
6924                         char            contype;
6925
6926                         indxinfo[j].dobj.objType = DO_INDEX;
6927                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6928                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6929                         AssignDumpId(&indxinfo[j].dobj);
6930                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
6931                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6932                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6933                         indxinfo[j].indextable = tbinfo;
6934                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
6935                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
6936                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
6937                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
6938                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnkeys * sizeof(Oid));
6939                         parseOidArray(PQgetvalue(res, j, i_indkey),
6940                                                   indxinfo[j].indkeys, indxinfo[j].indnkeys);
6941                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
6942                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
6943                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
6944                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
6945                         contype = *(PQgetvalue(res, j, i_contype));
6946
6947                         if (contype == 'p' || contype == 'u' || contype == 'x')
6948                         {
6949                                 /*
6950                                  * If we found a constraint matching the index, create an
6951                                  * entry for it.
6952                                  */
6953                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
6954                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6955                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
6956                                 AssignDumpId(&constrinfo[j].dobj);
6957                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
6958                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6959                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6960                                 constrinfo[j].contable = tbinfo;
6961                                 constrinfo[j].condomain = NULL;
6962                                 constrinfo[j].contype = contype;
6963                                 if (contype == 'x')
6964                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
6965                                 else
6966                                         constrinfo[j].condef = NULL;
6967                                 constrinfo[j].confrelid = InvalidOid;
6968                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
6969                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
6970                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
6971                                 constrinfo[j].conislocal = true;
6972                                 constrinfo[j].separate = true;
6973
6974                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
6975                         }
6976                         else
6977                         {
6978                                 /* Plain secondary index */
6979                                 indxinfo[j].indexconstraint = 0;
6980                         }
6981                 }
6982
6983                 PQclear(res);
6984         }
6985
6986         destroyPQExpBuffer(query);
6987 }
6988
6989 /*
6990  * getExtendedStatistics
6991  *        get information about extended-statistics objects.
6992  *
6993  * Note: extended statistics data is not returned directly to the caller, but
6994  * it does get entered into the DumpableObject tables.
6995  */
6996 void
6997 getExtendedStatistics(Archive *fout)
6998 {
6999         PQExpBuffer query;
7000         PGresult   *res;
7001         StatsExtInfo *statsextinfo;
7002         int                     ntups;
7003         int                     i_tableoid;
7004         int                     i_oid;
7005         int                     i_stxname;
7006         int                     i_stxnamespace;
7007         int                     i_rolname;
7008         int                     i;
7009
7010         /* Extended statistics were new in v10 */
7011         if (fout->remoteVersion < 100000)
7012                 return;
7013
7014         query = createPQExpBuffer();
7015
7016         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7017                                           "stxnamespace, (%s stxowner) AS rolname "
7018                                           "FROM pg_catalog.pg_statistic_ext",
7019                                           username_subquery);
7020
7021         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7022
7023         ntups = PQntuples(res);
7024
7025         i_tableoid = PQfnumber(res, "tableoid");
7026         i_oid = PQfnumber(res, "oid");
7027         i_stxname = PQfnumber(res, "stxname");
7028         i_stxnamespace = PQfnumber(res, "stxnamespace");
7029         i_rolname = PQfnumber(res, "rolname");
7030
7031         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7032
7033         for (i = 0; i < ntups; i++)
7034         {
7035                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7036                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7037                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7038                 AssignDumpId(&statsextinfo[i].dobj);
7039                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7040                 statsextinfo[i].dobj.namespace =
7041                         findNamespace(fout,
7042                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7043                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7044
7045                 /* Decide whether we want to dump it */
7046                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7047
7048                 /* Stats objects do not currently have ACLs. */
7049                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7050         }
7051
7052         PQclear(res);
7053         destroyPQExpBuffer(query);
7054 }
7055
7056 /*
7057  * getConstraints
7058  *
7059  * Get info about constraints on dumpable tables.
7060  *
7061  * Currently handles foreign keys only.
7062  * Unique and primary key constraints are handled with indexes,
7063  * while check constraints are processed in getTableAttrs().
7064  */
7065 void
7066 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7067 {
7068         int                     i,
7069                                 j;
7070         ConstraintInfo *constrinfo;
7071         PQExpBuffer query;
7072         PGresult   *res;
7073         int                     i_contableoid,
7074                                 i_conoid,
7075                                 i_conname,
7076                                 i_confrelid,
7077                                 i_condef;
7078         int                     ntups;
7079
7080         query = createPQExpBuffer();
7081
7082         for (i = 0; i < numTables; i++)
7083         {
7084                 TableInfo  *tbinfo = &tblinfo[i];
7085
7086                 if (!tbinfo->hastriggers ||
7087                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7088                         continue;
7089
7090                 if (g_verbose)
7091                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7092                                           tbinfo->dobj.namespace->dobj.name,
7093                                           tbinfo->dobj.name);
7094
7095                 resetPQExpBuffer(query);
7096                 appendPQExpBuffer(query,
7097                                                   "SELECT tableoid, oid, conname, confrelid, "
7098                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
7099                                                   "FROM pg_catalog.pg_constraint "
7100                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
7101                                                   "AND contype = 'f'",
7102                                                   tbinfo->dobj.catId.oid);
7103                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7104
7105                 ntups = PQntuples(res);
7106
7107                 i_contableoid = PQfnumber(res, "tableoid");
7108                 i_conoid = PQfnumber(res, "oid");
7109                 i_conname = PQfnumber(res, "conname");
7110                 i_confrelid = PQfnumber(res, "confrelid");
7111                 i_condef = PQfnumber(res, "condef");
7112
7113                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7114
7115                 for (j = 0; j < ntups; j++)
7116                 {
7117                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7118                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7119                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7120                         AssignDumpId(&constrinfo[j].dobj);
7121                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7122                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7123                         constrinfo[j].contable = tbinfo;
7124                         constrinfo[j].condomain = NULL;
7125                         constrinfo[j].contype = 'f';
7126                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7127                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7128                         constrinfo[j].conindex = 0;
7129                         constrinfo[j].condeferrable = false;
7130                         constrinfo[j].condeferred = false;
7131                         constrinfo[j].conislocal = true;
7132                         constrinfo[j].separate = true;
7133                 }
7134
7135                 PQclear(res);
7136         }
7137
7138         destroyPQExpBuffer(query);
7139 }
7140
7141 /*
7142  * getDomainConstraints
7143  *
7144  * Get info about constraints on a domain.
7145  */
7146 static void
7147 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7148 {
7149         int                     i;
7150         ConstraintInfo *constrinfo;
7151         PQExpBuffer query;
7152         PGresult   *res;
7153         int                     i_tableoid,
7154                                 i_oid,
7155                                 i_conname,
7156                                 i_consrc;
7157         int                     ntups;
7158
7159         query = createPQExpBuffer();
7160
7161         if (fout->remoteVersion >= 90100)
7162                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7163                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7164                                                   "convalidated "
7165                                                   "FROM pg_catalog.pg_constraint "
7166                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7167                                                   "ORDER BY conname",
7168                                                   tyinfo->dobj.catId.oid);
7169
7170         else
7171                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7172                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7173                                                   "true as convalidated "
7174                                                   "FROM pg_catalog.pg_constraint "
7175                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7176                                                   "ORDER BY conname",
7177                                                   tyinfo->dobj.catId.oid);
7178
7179         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7180
7181         ntups = PQntuples(res);
7182
7183         i_tableoid = PQfnumber(res, "tableoid");
7184         i_oid = PQfnumber(res, "oid");
7185         i_conname = PQfnumber(res, "conname");
7186         i_consrc = PQfnumber(res, "consrc");
7187
7188         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7189
7190         tyinfo->nDomChecks = ntups;
7191         tyinfo->domChecks = constrinfo;
7192
7193         for (i = 0; i < ntups; i++)
7194         {
7195                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7196
7197                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7198                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7199                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7200                 AssignDumpId(&constrinfo[i].dobj);
7201                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7202                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7203                 constrinfo[i].contable = NULL;
7204                 constrinfo[i].condomain = tyinfo;
7205                 constrinfo[i].contype = 'c';
7206                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7207                 constrinfo[i].confrelid = InvalidOid;
7208                 constrinfo[i].conindex = 0;
7209                 constrinfo[i].condeferrable = false;
7210                 constrinfo[i].condeferred = false;
7211                 constrinfo[i].conislocal = true;
7212
7213                 constrinfo[i].separate = !validated;
7214
7215                 /*
7216                  * Make the domain depend on the constraint, ensuring it won't be
7217                  * output till any constraint dependencies are OK.  If the constraint
7218                  * has not been validated, it's going to be dumped after the domain
7219                  * anyway, so this doesn't matter.
7220                  */
7221                 if (validated)
7222                         addObjectDependency(&tyinfo->dobj,
7223                                                                 constrinfo[i].dobj.dumpId);
7224         }
7225
7226         PQclear(res);
7227
7228         destroyPQExpBuffer(query);
7229 }
7230
7231 /*
7232  * getRules
7233  *        get basic information about every rule in the system
7234  *
7235  * numRules is set to the number of rules read in
7236  */
7237 RuleInfo *
7238 getRules(Archive *fout, int *numRules)
7239 {
7240         PGresult   *res;
7241         int                     ntups;
7242         int                     i;
7243         PQExpBuffer query = createPQExpBuffer();
7244         RuleInfo   *ruleinfo;
7245         int                     i_tableoid;
7246         int                     i_oid;
7247         int                     i_rulename;
7248         int                     i_ruletable;
7249         int                     i_ev_type;
7250         int                     i_is_instead;
7251         int                     i_ev_enabled;
7252
7253         if (fout->remoteVersion >= 80300)
7254         {
7255                 appendPQExpBufferStr(query, "SELECT "
7256                                                          "tableoid, oid, rulename, "
7257                                                          "ev_class AS ruletable, ev_type, is_instead, "
7258                                                          "ev_enabled "
7259                                                          "FROM pg_rewrite "
7260                                                          "ORDER BY oid");
7261         }
7262         else
7263         {
7264                 appendPQExpBufferStr(query, "SELECT "
7265                                                          "tableoid, oid, rulename, "
7266                                                          "ev_class AS ruletable, ev_type, is_instead, "
7267                                                          "'O'::char AS ev_enabled "
7268                                                          "FROM pg_rewrite "
7269                                                          "ORDER BY oid");
7270         }
7271
7272         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7273
7274         ntups = PQntuples(res);
7275
7276         *numRules = ntups;
7277
7278         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7279
7280         i_tableoid = PQfnumber(res, "tableoid");
7281         i_oid = PQfnumber(res, "oid");
7282         i_rulename = PQfnumber(res, "rulename");
7283         i_ruletable = PQfnumber(res, "ruletable");
7284         i_ev_type = PQfnumber(res, "ev_type");
7285         i_is_instead = PQfnumber(res, "is_instead");
7286         i_ev_enabled = PQfnumber(res, "ev_enabled");
7287
7288         for (i = 0; i < ntups; i++)
7289         {
7290                 Oid                     ruletableoid;
7291
7292                 ruleinfo[i].dobj.objType = DO_RULE;
7293                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7294                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7295                 AssignDumpId(&ruleinfo[i].dobj);
7296                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7297                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7298                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7299                 if (ruleinfo[i].ruletable == NULL)
7300                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7301                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7302                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7303                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7304                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7305                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7306                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7307                 if (ruleinfo[i].ruletable)
7308                 {
7309                         /*
7310                          * If the table is a view or materialized view, force its ON
7311                          * SELECT rule to be sorted before the view itself --- this
7312                          * ensures that any dependencies for the rule affect the table's
7313                          * positioning. Other rules are forced to appear after their
7314                          * table.
7315                          */
7316                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7317                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7318                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7319                         {
7320                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7321                                                                         ruleinfo[i].dobj.dumpId);
7322                                 /* We'll merge the rule into CREATE VIEW, if possible */
7323                                 ruleinfo[i].separate = false;
7324                         }
7325                         else
7326                         {
7327                                 addObjectDependency(&ruleinfo[i].dobj,
7328                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7329                                 ruleinfo[i].separate = true;
7330                         }
7331                 }
7332                 else
7333                         ruleinfo[i].separate = true;
7334         }
7335
7336         PQclear(res);
7337
7338         destroyPQExpBuffer(query);
7339
7340         return ruleinfo;
7341 }
7342
7343 /*
7344  * getTriggers
7345  *        get information about every trigger on a dumpable table
7346  *
7347  * Note: trigger data is not returned directly to the caller, but it
7348  * does get entered into the DumpableObject tables.
7349  */
7350 void
7351 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7352 {
7353         int                     i,
7354                                 j;
7355         PQExpBuffer query = createPQExpBuffer();
7356         PGresult   *res;
7357         TriggerInfo *tginfo;
7358         int                     i_tableoid,
7359                                 i_oid,
7360                                 i_tgname,
7361                                 i_tgfname,
7362                                 i_tgtype,
7363                                 i_tgnargs,
7364                                 i_tgargs,
7365                                 i_tgisconstraint,
7366                                 i_tgconstrname,
7367                                 i_tgconstrrelid,
7368                                 i_tgconstrrelname,
7369                                 i_tgenabled,
7370                                 i_tgdeferrable,
7371                                 i_tginitdeferred,
7372                                 i_tgdef;
7373         int                     ntups;
7374
7375         for (i = 0; i < numTables; i++)
7376         {
7377                 TableInfo  *tbinfo = &tblinfo[i];
7378
7379                 if (!tbinfo->hastriggers ||
7380                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7381                         continue;
7382
7383                 if (g_verbose)
7384                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7385                                           tbinfo->dobj.namespace->dobj.name,
7386                                           tbinfo->dobj.name);
7387
7388                 resetPQExpBuffer(query);
7389                 if (fout->remoteVersion >= 90000)
7390                 {
7391                         /*
7392                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7393                          * could result in non-forward-compatible dumps of WHEN clauses
7394                          * due to under-parenthesization.
7395                          */
7396                         appendPQExpBuffer(query,
7397                                                           "SELECT tgname, "
7398                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7399                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7400                                                           "tgenabled, tableoid, oid "
7401                                                           "FROM pg_catalog.pg_trigger t "
7402                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7403                                                           "AND NOT tgisinternal",
7404                                                           tbinfo->dobj.catId.oid);
7405                 }
7406                 else if (fout->remoteVersion >= 80300)
7407                 {
7408                         /*
7409                          * We ignore triggers that are tied to a foreign-key constraint
7410                          */
7411                         appendPQExpBuffer(query,
7412                                                           "SELECT tgname, "
7413                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7414                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7415                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7416                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7417                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7418                                                           "FROM pg_catalog.pg_trigger t "
7419                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7420                                                           "AND tgconstraint = 0",
7421                                                           tbinfo->dobj.catId.oid);
7422                 }
7423                 else
7424                 {
7425                         /*
7426                          * We ignore triggers that are tied to a foreign-key constraint,
7427                          * but in these versions we have to grovel through pg_constraint
7428                          * to find out
7429                          */
7430                         appendPQExpBuffer(query,
7431                                                           "SELECT tgname, "
7432                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7433                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7434                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7435                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7436                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7437                                                           "FROM pg_catalog.pg_trigger t "
7438                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7439                                                           "AND (NOT tgisconstraint "
7440                                                           " OR NOT EXISTS"
7441                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7442                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7443                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7444                                                           tbinfo->dobj.catId.oid);
7445                 }
7446
7447                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7448
7449                 ntups = PQntuples(res);
7450
7451                 i_tableoid = PQfnumber(res, "tableoid");
7452                 i_oid = PQfnumber(res, "oid");
7453                 i_tgname = PQfnumber(res, "tgname");
7454                 i_tgfname = PQfnumber(res, "tgfname");
7455                 i_tgtype = PQfnumber(res, "tgtype");
7456                 i_tgnargs = PQfnumber(res, "tgnargs");
7457                 i_tgargs = PQfnumber(res, "tgargs");
7458                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7459                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7460                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7461                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7462                 i_tgenabled = PQfnumber(res, "tgenabled");
7463                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7464                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7465                 i_tgdef = PQfnumber(res, "tgdef");
7466
7467                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7468
7469                 tbinfo->numTriggers = ntups;
7470                 tbinfo->triggers = tginfo;
7471
7472                 for (j = 0; j < ntups; j++)
7473                 {
7474                         tginfo[j].dobj.objType = DO_TRIGGER;
7475                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7476                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7477                         AssignDumpId(&tginfo[j].dobj);
7478                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7479                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7480                         tginfo[j].tgtable = tbinfo;
7481                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7482                         if (i_tgdef >= 0)
7483                         {
7484                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7485
7486                                 /* remaining fields are not valid if we have tgdef */
7487                                 tginfo[j].tgfname = NULL;
7488                                 tginfo[j].tgtype = 0;
7489                                 tginfo[j].tgnargs = 0;
7490                                 tginfo[j].tgargs = NULL;
7491                                 tginfo[j].tgisconstraint = false;
7492                                 tginfo[j].tgdeferrable = false;
7493                                 tginfo[j].tginitdeferred = false;
7494                                 tginfo[j].tgconstrname = NULL;
7495                                 tginfo[j].tgconstrrelid = InvalidOid;
7496                                 tginfo[j].tgconstrrelname = NULL;
7497                         }
7498                         else
7499                         {
7500                                 tginfo[j].tgdef = NULL;
7501
7502                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7503                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7504                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7505                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7506                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7507                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7508                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7509
7510                                 if (tginfo[j].tgisconstraint)
7511                                 {
7512                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7513                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7514                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7515                                         {
7516                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7517                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7518                                                                                   tginfo[j].dobj.name,
7519                                                                                   tbinfo->dobj.name,
7520                                                                                   tginfo[j].tgconstrrelid);
7521                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7522                                         }
7523                                         else
7524                                                 tginfo[j].tgconstrrelname = NULL;
7525                                 }
7526                                 else
7527                                 {
7528                                         tginfo[j].tgconstrname = NULL;
7529                                         tginfo[j].tgconstrrelid = InvalidOid;
7530                                         tginfo[j].tgconstrrelname = NULL;
7531                                 }
7532                         }
7533                 }
7534
7535                 PQclear(res);
7536         }
7537
7538         destroyPQExpBuffer(query);
7539 }
7540
7541 /*
7542  * getEventTriggers
7543  *        get information about event triggers
7544  */
7545 EventTriggerInfo *
7546 getEventTriggers(Archive *fout, int *numEventTriggers)
7547 {
7548         int                     i;
7549         PQExpBuffer query;
7550         PGresult   *res;
7551         EventTriggerInfo *evtinfo;
7552         int                     i_tableoid,
7553                                 i_oid,
7554                                 i_evtname,
7555                                 i_evtevent,
7556                                 i_evtowner,
7557                                 i_evttags,
7558                                 i_evtfname,
7559                                 i_evtenabled;
7560         int                     ntups;
7561
7562         /* Before 9.3, there are no event triggers */
7563         if (fout->remoteVersion < 90300)
7564         {
7565                 *numEventTriggers = 0;
7566                 return NULL;
7567         }
7568
7569         query = createPQExpBuffer();
7570
7571         appendPQExpBuffer(query,
7572                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7573                                           "evtevent, (%s evtowner) AS evtowner, "
7574                                           "array_to_string(array("
7575                                           "select quote_literal(x) "
7576                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7577                                           "e.evtfoid::regproc as evtfname "
7578                                           "FROM pg_event_trigger e "
7579                                           "ORDER BY e.oid",
7580                                           username_subquery);
7581
7582         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7583
7584         ntups = PQntuples(res);
7585
7586         *numEventTriggers = ntups;
7587
7588         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7589
7590         i_tableoid = PQfnumber(res, "tableoid");
7591         i_oid = PQfnumber(res, "oid");
7592         i_evtname = PQfnumber(res, "evtname");
7593         i_evtevent = PQfnumber(res, "evtevent");
7594         i_evtowner = PQfnumber(res, "evtowner");
7595         i_evttags = PQfnumber(res, "evttags");
7596         i_evtfname = PQfnumber(res, "evtfname");
7597         i_evtenabled = PQfnumber(res, "evtenabled");
7598
7599         for (i = 0; i < ntups; i++)
7600         {
7601                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7602                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7603                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7604                 AssignDumpId(&evtinfo[i].dobj);
7605                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7606                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7607                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7608                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7609                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7610                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7611                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7612
7613                 /* Decide whether we want to dump it */
7614                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7615
7616                 /* Event Triggers do not currently have ACLs. */
7617                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7618         }
7619
7620         PQclear(res);
7621
7622         destroyPQExpBuffer(query);
7623
7624         return evtinfo;
7625 }
7626
7627 /*
7628  * getProcLangs
7629  *        get basic information about every procedural language in the system
7630  *
7631  * numProcLangs is set to the number of langs read in
7632  *
7633  * NB: this must run after getFuncs() because we assume we can do
7634  * findFuncByOid().
7635  */
7636 ProcLangInfo *
7637 getProcLangs(Archive *fout, int *numProcLangs)
7638 {
7639         DumpOptions *dopt = fout->dopt;
7640         PGresult   *res;
7641         int                     ntups;
7642         int                     i;
7643         PQExpBuffer query = createPQExpBuffer();
7644         ProcLangInfo *planginfo;
7645         int                     i_tableoid;
7646         int                     i_oid;
7647         int                     i_lanname;
7648         int                     i_lanpltrusted;
7649         int                     i_lanplcallfoid;
7650         int                     i_laninline;
7651         int                     i_lanvalidator;
7652         int                     i_lanacl;
7653         int                     i_rlanacl;
7654         int                     i_initlanacl;
7655         int                     i_initrlanacl;
7656         int                     i_lanowner;
7657
7658         if (fout->remoteVersion >= 90600)
7659         {
7660                 PQExpBuffer acl_subquery = createPQExpBuffer();
7661                 PQExpBuffer racl_subquery = createPQExpBuffer();
7662                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7663                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7664
7665                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7666                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7667                                                 dopt->binary_upgrade);
7668
7669                 /* pg_language has a laninline column */
7670                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7671                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7672                                                   "l.laninline, l.lanvalidator, "
7673                                                   "%s AS lanacl, "
7674                                                   "%s AS rlanacl, "
7675                                                   "%s AS initlanacl, "
7676                                                   "%s AS initrlanacl, "
7677                                                   "(%s l.lanowner) AS lanowner "
7678                                                   "FROM pg_language l "
7679                                                   "LEFT JOIN pg_init_privs pip ON "
7680                                                   "(l.oid = pip.objoid "
7681                                                   "AND pip.classoid = 'pg_language'::regclass "
7682                                                   "AND pip.objsubid = 0) "
7683                                                   "WHERE l.lanispl "
7684                                                   "ORDER BY l.oid",
7685                                                   acl_subquery->data,
7686                                                   racl_subquery->data,
7687                                                   initacl_subquery->data,
7688                                                   initracl_subquery->data,
7689                                                   username_subquery);
7690
7691                 destroyPQExpBuffer(acl_subquery);
7692                 destroyPQExpBuffer(racl_subquery);
7693                 destroyPQExpBuffer(initacl_subquery);
7694                 destroyPQExpBuffer(initracl_subquery);
7695         }
7696         else if (fout->remoteVersion >= 90000)
7697         {
7698                 /* pg_language has a laninline column */
7699                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7700                                                   "lanname, lanpltrusted, lanplcallfoid, "
7701                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7702                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7703                                                   "(%s lanowner) AS lanowner "
7704                                                   "FROM pg_language "
7705                                                   "WHERE lanispl "
7706                                                   "ORDER BY oid",
7707                                                   username_subquery);
7708         }
7709         else if (fout->remoteVersion >= 80300)
7710         {
7711                 /* pg_language has a lanowner column */
7712                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7713                                                   "lanname, lanpltrusted, lanplcallfoid, "
7714                                                   "0 AS laninline, lanvalidator, lanacl, "
7715                                                   "NULL AS rlanacl, "
7716                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7717                                                   "(%s lanowner) AS lanowner "
7718                                                   "FROM pg_language "
7719                                                   "WHERE lanispl "
7720                                                   "ORDER BY oid",
7721                                                   username_subquery);
7722         }
7723         else if (fout->remoteVersion >= 80100)
7724         {
7725                 /* Languages are owned by the bootstrap superuser, OID 10 */
7726                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7727                                                   "lanname, lanpltrusted, lanplcallfoid, "
7728                                                   "0 AS laninline, lanvalidator, lanacl, "
7729                                                   "NULL AS rlanacl, "
7730                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7731                                                   "(%s '10') AS lanowner "
7732                                                   "FROM pg_language "
7733                                                   "WHERE lanispl "
7734                                                   "ORDER BY oid",
7735                                                   username_subquery);
7736         }
7737         else
7738         {
7739                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7740                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7741                                                   "lanname, lanpltrusted, lanplcallfoid, "
7742                                                   "0 AS laninline, lanvalidator, lanacl, "
7743                                                   "NULL AS rlanacl, "
7744                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7745                                                   "(%s '1') AS lanowner "
7746                                                   "FROM pg_language "
7747                                                   "WHERE lanispl "
7748                                                   "ORDER BY oid",
7749                                                   username_subquery);
7750         }
7751
7752         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7753
7754         ntups = PQntuples(res);
7755
7756         *numProcLangs = ntups;
7757
7758         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7759
7760         i_tableoid = PQfnumber(res, "tableoid");
7761         i_oid = PQfnumber(res, "oid");
7762         i_lanname = PQfnumber(res, "lanname");
7763         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7764         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7765         i_laninline = PQfnumber(res, "laninline");
7766         i_lanvalidator = PQfnumber(res, "lanvalidator");
7767         i_lanacl = PQfnumber(res, "lanacl");
7768         i_rlanacl = PQfnumber(res, "rlanacl");
7769         i_initlanacl = PQfnumber(res, "initlanacl");
7770         i_initrlanacl = PQfnumber(res, "initrlanacl");
7771         i_lanowner = PQfnumber(res, "lanowner");
7772
7773         for (i = 0; i < ntups; i++)
7774         {
7775                 planginfo[i].dobj.objType = DO_PROCLANG;
7776                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7777                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7778                 AssignDumpId(&planginfo[i].dobj);
7779
7780                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7781                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7782                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7783                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7784                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7785                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7786                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7787                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7788                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7789                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7790
7791                 /* Decide whether we want to dump it */
7792                 selectDumpableProcLang(&(planginfo[i]), fout);
7793
7794                 /* Do not try to dump ACL if no ACL exists. */
7795                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7796                         PQgetisnull(res, i, i_initlanacl) &&
7797                         PQgetisnull(res, i, i_initrlanacl))
7798                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7799         }
7800
7801         PQclear(res);
7802
7803         destroyPQExpBuffer(query);
7804
7805         return planginfo;
7806 }
7807
7808 /*
7809  * getCasts
7810  *        get basic information about every cast in the system
7811  *
7812  * numCasts is set to the number of casts read in
7813  */
7814 CastInfo *
7815 getCasts(Archive *fout, int *numCasts)
7816 {
7817         PGresult   *res;
7818         int                     ntups;
7819         int                     i;
7820         PQExpBuffer query = createPQExpBuffer();
7821         CastInfo   *castinfo;
7822         int                     i_tableoid;
7823         int                     i_oid;
7824         int                     i_castsource;
7825         int                     i_casttarget;
7826         int                     i_castfunc;
7827         int                     i_castcontext;
7828         int                     i_castmethod;
7829
7830         if (fout->remoteVersion >= 80400)
7831         {
7832                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7833                                                          "castsource, casttarget, castfunc, castcontext, "
7834                                                          "castmethod "
7835                                                          "FROM pg_cast ORDER BY 3,4");
7836         }
7837         else
7838         {
7839                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7840                                                          "castsource, casttarget, castfunc, castcontext, "
7841                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7842                                                          "FROM pg_cast ORDER BY 3,4");
7843         }
7844
7845         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7846
7847         ntups = PQntuples(res);
7848
7849         *numCasts = ntups;
7850
7851         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7852
7853         i_tableoid = PQfnumber(res, "tableoid");
7854         i_oid = PQfnumber(res, "oid");
7855         i_castsource = PQfnumber(res, "castsource");
7856         i_casttarget = PQfnumber(res, "casttarget");
7857         i_castfunc = PQfnumber(res, "castfunc");
7858         i_castcontext = PQfnumber(res, "castcontext");
7859         i_castmethod = PQfnumber(res, "castmethod");
7860
7861         for (i = 0; i < ntups; i++)
7862         {
7863                 PQExpBufferData namebuf;
7864                 TypeInfo   *sTypeInfo;
7865                 TypeInfo   *tTypeInfo;
7866
7867                 castinfo[i].dobj.objType = DO_CAST;
7868                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7869                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7870                 AssignDumpId(&castinfo[i].dobj);
7871                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7872                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7873                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7874                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7875                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7876
7877                 /*
7878                  * Try to name cast as concatenation of typnames.  This is only used
7879                  * for purposes of sorting.  If we fail to find either type, the name
7880                  * will be an empty string.
7881                  */
7882                 initPQExpBuffer(&namebuf);
7883                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
7884                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7885                 if (sTypeInfo && tTypeInfo)
7886                         appendPQExpBuffer(&namebuf, "%s %s",
7887                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7888                 castinfo[i].dobj.name = namebuf.data;
7889
7890                 /* Decide whether we want to dump it */
7891                 selectDumpableCast(&(castinfo[i]), fout);
7892
7893                 /* Casts do not currently have ACLs. */
7894                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7895         }
7896
7897         PQclear(res);
7898
7899         destroyPQExpBuffer(query);
7900
7901         return castinfo;
7902 }
7903
7904 static char *
7905 get_language_name(Archive *fout, Oid langid)
7906 {
7907         PQExpBuffer query;
7908         PGresult   *res;
7909         char       *lanname;
7910
7911         query = createPQExpBuffer();
7912         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
7913         res = ExecuteSqlQueryForSingleRow(fout, query->data);
7914         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
7915         destroyPQExpBuffer(query);
7916         PQclear(res);
7917
7918         return lanname;
7919 }
7920
7921 /*
7922  * getTransforms
7923  *        get basic information about every transform in the system
7924  *
7925  * numTransforms is set to the number of transforms read in
7926  */
7927 TransformInfo *
7928 getTransforms(Archive *fout, int *numTransforms)
7929 {
7930         PGresult   *res;
7931         int                     ntups;
7932         int                     i;
7933         PQExpBuffer query;
7934         TransformInfo *transforminfo;
7935         int                     i_tableoid;
7936         int                     i_oid;
7937         int                     i_trftype;
7938         int                     i_trflang;
7939         int                     i_trffromsql;
7940         int                     i_trftosql;
7941
7942         /* Transforms didn't exist pre-9.5 */
7943         if (fout->remoteVersion < 90500)
7944         {
7945                 *numTransforms = 0;
7946                 return NULL;
7947         }
7948
7949         query = createPQExpBuffer();
7950
7951         appendPQExpBuffer(query, "SELECT tableoid, oid, "
7952                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
7953                                           "FROM pg_transform "
7954                                           "ORDER BY 3,4");
7955
7956         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7957
7958         ntups = PQntuples(res);
7959
7960         *numTransforms = ntups;
7961
7962         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
7963
7964         i_tableoid = PQfnumber(res, "tableoid");
7965         i_oid = PQfnumber(res, "oid");
7966         i_trftype = PQfnumber(res, "trftype");
7967         i_trflang = PQfnumber(res, "trflang");
7968         i_trffromsql = PQfnumber(res, "trffromsql");
7969         i_trftosql = PQfnumber(res, "trftosql");
7970
7971         for (i = 0; i < ntups; i++)
7972         {
7973                 PQExpBufferData namebuf;
7974                 TypeInfo   *typeInfo;
7975                 char       *lanname;
7976
7977                 transforminfo[i].dobj.objType = DO_TRANSFORM;
7978                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7979                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7980                 AssignDumpId(&transforminfo[i].dobj);
7981                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
7982                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
7983                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
7984                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
7985
7986                 /*
7987                  * Try to name transform as concatenation of type and language name.
7988                  * This is only used for purposes of sorting.  If we fail to find
7989                  * either, the name will be an empty string.
7990                  */
7991                 initPQExpBuffer(&namebuf);
7992                 typeInfo = findTypeByOid(transforminfo[i].trftype);
7993                 lanname = get_language_name(fout, transforminfo[i].trflang);
7994                 if (typeInfo && lanname)
7995                         appendPQExpBuffer(&namebuf, "%s %s",
7996                                                           typeInfo->dobj.name, lanname);
7997                 transforminfo[i].dobj.name = namebuf.data;
7998                 free(lanname);
7999
8000                 /* Decide whether we want to dump it */
8001                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8002         }
8003
8004         PQclear(res);
8005
8006         destroyPQExpBuffer(query);
8007
8008         return transforminfo;
8009 }
8010
8011 /*
8012  * getTableAttrs -
8013  *        for each interesting table, read info about its attributes
8014  *        (names, types, default values, CHECK constraints, etc)
8015  *
8016  * This is implemented in a very inefficient way right now, looping
8017  * through the tblinfo and doing a join per table to find the attrs and their
8018  * types.  However, because we want type names and so forth to be named
8019  * relative to the schema of each table, we couldn't do it in just one
8020  * query.  (Maybe one query per schema?)
8021  *
8022  *      modifies tblinfo
8023  */
8024 void
8025 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8026 {
8027         DumpOptions *dopt = fout->dopt;
8028         int                     i,
8029                                 j;
8030         PQExpBuffer q = createPQExpBuffer();
8031         int                     i_attnum;
8032         int                     i_attname;
8033         int                     i_atttypname;
8034         int                     i_atttypmod;
8035         int                     i_attstattarget;
8036         int                     i_attstorage;
8037         int                     i_typstorage;
8038         int                     i_attnotnull;
8039         int                     i_atthasdef;
8040         int                     i_attidentity;
8041         int                     i_attisdropped;
8042         int                     i_attlen;
8043         int                     i_attalign;
8044         int                     i_attislocal;
8045         int                     i_attoptions;
8046         int                     i_attcollation;
8047         int                     i_attfdwoptions;
8048         PGresult   *res;
8049         int                     ntups;
8050         bool            hasdefaults;
8051
8052         for (i = 0; i < numTables; i++)
8053         {
8054                 TableInfo  *tbinfo = &tblinfo[i];
8055
8056                 /* Don't bother to collect info for sequences */
8057                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8058                         continue;
8059
8060                 /* Don't bother with uninteresting tables, either */
8061                 if (!tbinfo->interesting)
8062                         continue;
8063
8064                 /* find all the user attributes and their types */
8065
8066                 /*
8067                  * we must read the attribute names in attribute number order! because
8068                  * we will use the attnum to index into the attnames array later.
8069                  */
8070                 if (g_verbose)
8071                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8072                                           tbinfo->dobj.namespace->dobj.name,
8073                                           tbinfo->dobj.name);
8074
8075                 resetPQExpBuffer(q);
8076
8077                 if (fout->remoteVersion >= 100000)
8078                 {
8079                         /*
8080                          * attidentity is new in version 10.
8081                          */
8082                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8083                                                           "a.attstattarget, a.attstorage, t.typstorage, "
8084                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
8085                                                           "a.attlen, a.attalign, a.attislocal, "
8086                                                           "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8087                                                           "array_to_string(a.attoptions, ', ') AS attoptions, "
8088                                                           "CASE WHEN a.attcollation <> t.typcollation "
8089                                                           "THEN a.attcollation ELSE 0 END AS attcollation, "
8090                                                           "a.attidentity, "
8091                                                           "pg_catalog.array_to_string(ARRAY("
8092                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8093                                                           "' ' || pg_catalog.quote_literal(option_value) "
8094                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8095                                                           "ORDER BY option_name"
8096                                                           "), E',\n    ') AS attfdwoptions "
8097                                                           "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8098                                                           "ON a.atttypid = t.oid "
8099                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
8100                                                           "AND a.attnum > 0::pg_catalog.int2 "
8101                                                           "ORDER BY a.attnum",
8102                                                           tbinfo->dobj.catId.oid);
8103                 }
8104                 else if (fout->remoteVersion >= 90200)
8105                 {
8106                         /*
8107                          * attfdwoptions is new in 9.2.
8108                          */
8109                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8110                                                           "a.attstattarget, a.attstorage, t.typstorage, "
8111                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
8112                                                           "a.attlen, a.attalign, a.attislocal, "
8113                                                           "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8114                                                           "array_to_string(a.attoptions, ', ') AS attoptions, "
8115                                                           "CASE WHEN a.attcollation <> t.typcollation "
8116                                                           "THEN a.attcollation ELSE 0 END AS attcollation, "
8117                                                           "pg_catalog.array_to_string(ARRAY("
8118                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8119                                                           "' ' || pg_catalog.quote_literal(option_value) "
8120                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8121                                                           "ORDER BY option_name"
8122                                                           "), E',\n    ') AS attfdwoptions "
8123                                                           "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8124                                                           "ON a.atttypid = t.oid "
8125                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
8126                                                           "AND a.attnum > 0::pg_catalog.int2 "
8127                                                           "ORDER BY a.attnum",
8128                                                           tbinfo->dobj.catId.oid);
8129                 }
8130                 else if (fout->remoteVersion >= 90100)
8131                 {
8132                         /*
8133                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
8134                          * clauses for attributes whose collation is different from their
8135                          * type's default, we use a CASE here to suppress uninteresting
8136                          * attcollations cheaply.
8137                          */
8138                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8139                                                           "a.attstattarget, a.attstorage, t.typstorage, "
8140                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
8141                                                           "a.attlen, a.attalign, a.attislocal, "
8142                                                           "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8143                                                           "array_to_string(a.attoptions, ', ') AS attoptions, "
8144                                                           "CASE WHEN a.attcollation <> t.typcollation "
8145                                                           "THEN a.attcollation ELSE 0 END AS attcollation, "
8146                                                           "NULL AS attfdwoptions "
8147                                                           "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8148                                                           "ON a.atttypid = t.oid "
8149                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
8150                                                           "AND a.attnum > 0::pg_catalog.int2 "
8151                                                           "ORDER BY a.attnum",
8152                                                           tbinfo->dobj.catId.oid);
8153                 }
8154                 else if (fout->remoteVersion >= 90000)
8155                 {
8156                         /* attoptions is new in 9.0 */
8157                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8158                                                           "a.attstattarget, a.attstorage, t.typstorage, "
8159                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
8160                                                           "a.attlen, a.attalign, a.attislocal, "
8161                                                           "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8162                                                           "array_to_string(a.attoptions, ', ') AS attoptions, "
8163                                                           "0 AS attcollation, "
8164                                                           "NULL AS attfdwoptions "
8165                                                           "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8166                                                           "ON a.atttypid = t.oid "
8167                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
8168                                                           "AND a.attnum > 0::pg_catalog.int2 "
8169                                                           "ORDER BY a.attnum",
8170                                                           tbinfo->dobj.catId.oid);
8171                 }
8172                 else
8173                 {
8174                         /* need left join here to not fail on dropped columns ... */
8175                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8176                                                           "a.attstattarget, a.attstorage, t.typstorage, "
8177                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
8178                                                           "a.attlen, a.attalign, a.attislocal, "
8179                                                           "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8180                                                           "'' AS attoptions, 0 AS attcollation, "
8181                                                           "NULL AS attfdwoptions "
8182                                                           "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8183                                                           "ON a.atttypid = t.oid "
8184                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
8185                                                           "AND a.attnum > 0::pg_catalog.int2 "
8186                                                           "ORDER BY a.attnum",
8187                                                           tbinfo->dobj.catId.oid);
8188                 }
8189
8190                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8191
8192                 ntups = PQntuples(res);
8193
8194                 i_attnum = PQfnumber(res, "attnum");
8195                 i_attname = PQfnumber(res, "attname");
8196                 i_atttypname = PQfnumber(res, "atttypname");
8197                 i_atttypmod = PQfnumber(res, "atttypmod");
8198                 i_attstattarget = PQfnumber(res, "attstattarget");
8199                 i_attstorage = PQfnumber(res, "attstorage");
8200                 i_typstorage = PQfnumber(res, "typstorage");
8201                 i_attnotnull = PQfnumber(res, "attnotnull");
8202                 i_atthasdef = PQfnumber(res, "atthasdef");
8203                 i_attidentity = PQfnumber(res, "attidentity");
8204                 i_attisdropped = PQfnumber(res, "attisdropped");
8205                 i_attlen = PQfnumber(res, "attlen");
8206                 i_attalign = PQfnumber(res, "attalign");
8207                 i_attislocal = PQfnumber(res, "attislocal");
8208                 i_attoptions = PQfnumber(res, "attoptions");
8209                 i_attcollation = PQfnumber(res, "attcollation");
8210                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
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->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8228                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8229                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8230                 hasdefaults = false;
8231
8232                 for (j = 0; j < ntups; j++)
8233                 {
8234                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8235                                 exit_horribly(NULL,
8236                                                           "invalid column numbering in table \"%s\"\n",
8237                                                           tbinfo->dobj.name);
8238                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8239                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8240                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8241                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8242                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8243                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8244                         tbinfo->attidentity[j] = (i_attidentity >= 0 ? *(PQgetvalue(res, j, i_attidentity)) : '\0');
8245                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8246                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8247                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8248                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8249                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8250                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8251                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8252                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8253                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8254                         tbinfo->attrdefs[j] = NULL; /* fix below */
8255                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8256                                 hasdefaults = true;
8257                         /* these flags will be set in flagInhAttrs() */
8258                         tbinfo->inhNotNull[j] = false;
8259                 }
8260
8261                 PQclear(res);
8262
8263                 /*
8264                  * Get info about column defaults
8265                  */
8266                 if (hasdefaults)
8267                 {
8268                         AttrDefInfo *attrdefs;
8269                         int                     numDefaults;
8270
8271                         if (g_verbose)
8272                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8273                                                   tbinfo->dobj.namespace->dobj.name,
8274                                                   tbinfo->dobj.name);
8275
8276                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8277                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8278                                                           "FROM pg_catalog.pg_attrdef "
8279                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8280                                                           tbinfo->dobj.catId.oid);
8281
8282                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8283
8284                         numDefaults = PQntuples(res);
8285                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8286
8287                         for (j = 0; j < numDefaults; j++)
8288                         {
8289                                 int                     adnum;
8290
8291                                 adnum = atoi(PQgetvalue(res, j, 2));
8292
8293                                 if (adnum <= 0 || adnum > ntups)
8294                                         exit_horribly(NULL,
8295                                                                   "invalid adnum value %d for table \"%s\"\n",
8296                                                                   adnum, tbinfo->dobj.name);
8297
8298                                 /*
8299                                  * dropped columns shouldn't have defaults, but just in case,
8300                                  * ignore 'em
8301                                  */
8302                                 if (tbinfo->attisdropped[adnum - 1])
8303                                         continue;
8304
8305                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8306                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8307                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8308                                 AssignDumpId(&attrdefs[j].dobj);
8309                                 attrdefs[j].adtable = tbinfo;
8310                                 attrdefs[j].adnum = adnum;
8311                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8312
8313                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8314                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8315
8316                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8317
8318                                 /*
8319                                  * Defaults on a VIEW must always be dumped as separate ALTER
8320                                  * TABLE commands.  Defaults on regular tables are dumped as
8321                                  * part of the CREATE TABLE if possible, which it won't be if
8322                                  * the column is not going to be emitted explicitly.
8323                                  */
8324                                 if (tbinfo->relkind == RELKIND_VIEW)
8325                                 {
8326                                         attrdefs[j].separate = true;
8327                                 }
8328                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8329                                 {
8330                                         /* column will be suppressed, print default separately */
8331                                         attrdefs[j].separate = true;
8332                                 }
8333                                 else
8334                                 {
8335                                         attrdefs[j].separate = false;
8336
8337                                         /*
8338                                          * Mark the default as needing to appear before the table,
8339                                          * so that any dependencies it has must be emitted before
8340                                          * the CREATE TABLE.  If this is not possible, we'll
8341                                          * change to "separate" mode while sorting dependencies.
8342                                          */
8343                                         addObjectDependency(&tbinfo->dobj,
8344                                                                                 attrdefs[j].dobj.dumpId);
8345                                 }
8346
8347                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8348                         }
8349                         PQclear(res);
8350                 }
8351
8352                 /*
8353                  * Get info about table CHECK constraints
8354                  */
8355                 if (tbinfo->ncheck > 0)
8356                 {
8357                         ConstraintInfo *constrs;
8358                         int                     numConstrs;
8359
8360                         if (g_verbose)
8361                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8362                                                   tbinfo->dobj.namespace->dobj.name,
8363                                                   tbinfo->dobj.name);
8364
8365                         resetPQExpBuffer(q);
8366                         if (fout->remoteVersion >= 90200)
8367                         {
8368                                 /*
8369                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8370                                  * but it wasn't ever false for check constraints until 9.2).
8371                                  */
8372                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8373                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8374                                                                   "conislocal, convalidated "
8375                                                                   "FROM pg_catalog.pg_constraint "
8376                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8377                                                                   "   AND contype = 'c' "
8378                                                                   "ORDER BY conname",
8379                                                                   tbinfo->dobj.catId.oid);
8380                         }
8381                         else if (fout->remoteVersion >= 80400)
8382                         {
8383                                 /* conislocal is new in 8.4 */
8384                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8385                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8386                                                                   "conislocal, true AS convalidated "
8387                                                                   "FROM pg_catalog.pg_constraint "
8388                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8389                                                                   "   AND contype = 'c' "
8390                                                                   "ORDER BY conname",
8391                                                                   tbinfo->dobj.catId.oid);
8392                         }
8393                         else
8394                         {
8395                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8396                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8397                                                                   "true AS conislocal, true AS convalidated "
8398                                                                   "FROM pg_catalog.pg_constraint "
8399                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8400                                                                   "   AND contype = 'c' "
8401                                                                   "ORDER BY conname",
8402                                                                   tbinfo->dobj.catId.oid);
8403                         }
8404
8405                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8406
8407                         numConstrs = PQntuples(res);
8408                         if (numConstrs != tbinfo->ncheck)
8409                         {
8410                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8411                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8412                                                                                  tbinfo->ncheck),
8413                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8414                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8415                                 exit_nicely(1);
8416                         }
8417
8418                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8419                         tbinfo->checkexprs = constrs;
8420
8421                         for (j = 0; j < numConstrs; j++)
8422                         {
8423                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8424
8425                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8426                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8427                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8428                                 AssignDumpId(&constrs[j].dobj);
8429                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8430                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8431                                 constrs[j].contable = tbinfo;
8432                                 constrs[j].condomain = NULL;
8433                                 constrs[j].contype = 'c';
8434                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8435                                 constrs[j].confrelid = InvalidOid;
8436                                 constrs[j].conindex = 0;
8437                                 constrs[j].condeferrable = false;
8438                                 constrs[j].condeferred = false;
8439                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8440
8441                                 /*
8442                                  * An unvalidated constraint needs to be dumped separately, so
8443                                  * that potentially-violating existing data is loaded before
8444                                  * the constraint.
8445                                  */
8446                                 constrs[j].separate = !validated;
8447
8448                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8449
8450                                 /*
8451                                  * Mark the constraint as needing to appear before the table
8452                                  * --- this is so that any other dependencies of the
8453                                  * constraint will be emitted before we try to create the
8454                                  * table.  If the constraint is to be dumped separately, it
8455                                  * will be dumped after data is loaded anyway, so don't do it.
8456                                  * (There's an automatic dependency in the opposite direction
8457                                  * anyway, so don't need to add one manually here.)
8458                                  */
8459                                 if (!constrs[j].separate)
8460                                         addObjectDependency(&tbinfo->dobj,
8461                                                                                 constrs[j].dobj.dumpId);
8462
8463                                 /*
8464                                  * If the constraint is inherited, this will be detected later
8465                                  * (in pre-8.4 databases).  We also detect later if the
8466                                  * constraint must be split out from the table definition.
8467                                  */
8468                         }
8469                         PQclear(res);
8470                 }
8471         }
8472
8473         destroyPQExpBuffer(q);
8474 }
8475
8476 /*
8477  * Test whether a column should be printed as part of table's CREATE TABLE.
8478  * Column number is zero-based.
8479  *
8480  * Normally this is always true, but it's false for dropped columns, as well
8481  * as those that were inherited without any local definition.  (If we print
8482  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8483  * However, in binary_upgrade mode, we must print all such columns anyway and
8484  * fix the attislocal/attisdropped state later, so as to keep control of the
8485  * physical column order.
8486  *
8487  * This function exists because there are scattered nonobvious places that
8488  * must be kept in sync with this decision.
8489  */
8490 bool
8491 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8492 {
8493         if (dopt->binary_upgrade)
8494                 return true;
8495         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8496 }
8497
8498
8499 /*
8500  * getTSParsers:
8501  *        read all text search parsers in the system catalogs and return them
8502  *        in the TSParserInfo* structure
8503  *
8504  *      numTSParsers is set to the number of parsers read in
8505  */
8506 TSParserInfo *
8507 getTSParsers(Archive *fout, int *numTSParsers)
8508 {
8509         PGresult   *res;
8510         int                     ntups;
8511         int                     i;
8512         PQExpBuffer query;
8513         TSParserInfo *prsinfo;
8514         int                     i_tableoid;
8515         int                     i_oid;
8516         int                     i_prsname;
8517         int                     i_prsnamespace;
8518         int                     i_prsstart;
8519         int                     i_prstoken;
8520         int                     i_prsend;
8521         int                     i_prsheadline;
8522         int                     i_prslextype;
8523
8524         /* Before 8.3, there is no built-in text search support */
8525         if (fout->remoteVersion < 80300)
8526         {
8527                 *numTSParsers = 0;
8528                 return NULL;
8529         }
8530
8531         query = createPQExpBuffer();
8532
8533         /*
8534          * find all text search objects, including builtin ones; we filter out
8535          * system-defined objects at dump-out time.
8536          */
8537
8538         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8539                                                  "prsstart::oid, prstoken::oid, "
8540                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8541                                                  "FROM pg_ts_parser");
8542
8543         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8544
8545         ntups = PQntuples(res);
8546         *numTSParsers = ntups;
8547
8548         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8549
8550         i_tableoid = PQfnumber(res, "tableoid");
8551         i_oid = PQfnumber(res, "oid");
8552         i_prsname = PQfnumber(res, "prsname");
8553         i_prsnamespace = PQfnumber(res, "prsnamespace");
8554         i_prsstart = PQfnumber(res, "prsstart");
8555         i_prstoken = PQfnumber(res, "prstoken");
8556         i_prsend = PQfnumber(res, "prsend");
8557         i_prsheadline = PQfnumber(res, "prsheadline");
8558         i_prslextype = PQfnumber(res, "prslextype");
8559
8560         for (i = 0; i < ntups; i++)
8561         {
8562                 prsinfo[i].dobj.objType = DO_TSPARSER;
8563                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8564                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8565                 AssignDumpId(&prsinfo[i].dobj);
8566                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8567                 prsinfo[i].dobj.namespace =
8568                         findNamespace(fout,
8569                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8570                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8571                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8572                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8573                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8574                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8575
8576                 /* Decide whether we want to dump it */
8577                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8578
8579                 /* Text Search Parsers do not currently have ACLs. */
8580                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8581         }
8582
8583         PQclear(res);
8584
8585         destroyPQExpBuffer(query);
8586
8587         return prsinfo;
8588 }
8589
8590 /*
8591  * getTSDictionaries:
8592  *        read all text search dictionaries in the system catalogs and return them
8593  *        in the TSDictInfo* structure
8594  *
8595  *      numTSDicts is set to the number of dictionaries read in
8596  */
8597 TSDictInfo *
8598 getTSDictionaries(Archive *fout, int *numTSDicts)
8599 {
8600         PGresult   *res;
8601         int                     ntups;
8602         int                     i;
8603         PQExpBuffer query;
8604         TSDictInfo *dictinfo;
8605         int                     i_tableoid;
8606         int                     i_oid;
8607         int                     i_dictname;
8608         int                     i_dictnamespace;
8609         int                     i_rolname;
8610         int                     i_dicttemplate;
8611         int                     i_dictinitoption;
8612
8613         /* Before 8.3, there is no built-in text search support */
8614         if (fout->remoteVersion < 80300)
8615         {
8616                 *numTSDicts = 0;
8617                 return NULL;
8618         }
8619
8620         query = createPQExpBuffer();
8621
8622         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8623                                           "dictnamespace, (%s dictowner) AS rolname, "
8624                                           "dicttemplate, dictinitoption "
8625                                           "FROM pg_ts_dict",
8626                                           username_subquery);
8627
8628         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8629
8630         ntups = PQntuples(res);
8631         *numTSDicts = ntups;
8632
8633         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8634
8635         i_tableoid = PQfnumber(res, "tableoid");
8636         i_oid = PQfnumber(res, "oid");
8637         i_dictname = PQfnumber(res, "dictname");
8638         i_dictnamespace = PQfnumber(res, "dictnamespace");
8639         i_rolname = PQfnumber(res, "rolname");
8640         i_dictinitoption = PQfnumber(res, "dictinitoption");
8641         i_dicttemplate = PQfnumber(res, "dicttemplate");
8642
8643         for (i = 0; i < ntups; i++)
8644         {
8645                 dictinfo[i].dobj.objType = DO_TSDICT;
8646                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8647                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8648                 AssignDumpId(&dictinfo[i].dobj);
8649                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8650                 dictinfo[i].dobj.namespace =
8651                         findNamespace(fout,
8652                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8653                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8654                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8655                 if (PQgetisnull(res, i, i_dictinitoption))
8656                         dictinfo[i].dictinitoption = NULL;
8657                 else
8658                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8659
8660                 /* Decide whether we want to dump it */
8661                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8662
8663                 /* Text Search Dictionaries do not currently have ACLs. */
8664                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8665         }
8666
8667         PQclear(res);
8668
8669         destroyPQExpBuffer(query);
8670
8671         return dictinfo;
8672 }
8673
8674 /*
8675  * getTSTemplates:
8676  *        read all text search templates in the system catalogs and return them
8677  *        in the TSTemplateInfo* structure
8678  *
8679  *      numTSTemplates is set to the number of templates read in
8680  */
8681 TSTemplateInfo *
8682 getTSTemplates(Archive *fout, int *numTSTemplates)
8683 {
8684         PGresult   *res;
8685         int                     ntups;
8686         int                     i;
8687         PQExpBuffer query;
8688         TSTemplateInfo *tmplinfo;
8689         int                     i_tableoid;
8690         int                     i_oid;
8691         int                     i_tmplname;
8692         int                     i_tmplnamespace;
8693         int                     i_tmplinit;
8694         int                     i_tmpllexize;
8695
8696         /* Before 8.3, there is no built-in text search support */
8697         if (fout->remoteVersion < 80300)
8698         {
8699                 *numTSTemplates = 0;
8700                 return NULL;
8701         }
8702
8703         query = createPQExpBuffer();
8704
8705         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8706                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8707                                                  "FROM pg_ts_template");
8708
8709         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8710
8711         ntups = PQntuples(res);
8712         *numTSTemplates = ntups;
8713
8714         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8715
8716         i_tableoid = PQfnumber(res, "tableoid");
8717         i_oid = PQfnumber(res, "oid");
8718         i_tmplname = PQfnumber(res, "tmplname");
8719         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8720         i_tmplinit = PQfnumber(res, "tmplinit");
8721         i_tmpllexize = PQfnumber(res, "tmpllexize");
8722
8723         for (i = 0; i < ntups; i++)
8724         {
8725                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8726                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8727                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8728                 AssignDumpId(&tmplinfo[i].dobj);
8729                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8730                 tmplinfo[i].dobj.namespace =
8731                         findNamespace(fout,
8732                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8733                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8734                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8735
8736                 /* Decide whether we want to dump it */
8737                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8738
8739                 /* Text Search Templates do not currently have ACLs. */
8740                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8741         }
8742
8743         PQclear(res);
8744
8745         destroyPQExpBuffer(query);
8746
8747         return tmplinfo;
8748 }
8749
8750 /*
8751  * getTSConfigurations:
8752  *        read all text search configurations in the system catalogs and return
8753  *        them in the TSConfigInfo* structure
8754  *
8755  *      numTSConfigs is set to the number of configurations read in
8756  */
8757 TSConfigInfo *
8758 getTSConfigurations(Archive *fout, int *numTSConfigs)
8759 {
8760         PGresult   *res;
8761         int                     ntups;
8762         int                     i;
8763         PQExpBuffer query;
8764         TSConfigInfo *cfginfo;
8765         int                     i_tableoid;
8766         int                     i_oid;
8767         int                     i_cfgname;
8768         int                     i_cfgnamespace;
8769         int                     i_rolname;
8770         int                     i_cfgparser;
8771
8772         /* Before 8.3, there is no built-in text search support */
8773         if (fout->remoteVersion < 80300)
8774         {
8775                 *numTSConfigs = 0;
8776                 return NULL;
8777         }
8778
8779         query = createPQExpBuffer();
8780
8781         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8782                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8783                                           "FROM pg_ts_config",
8784                                           username_subquery);
8785
8786         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8787
8788         ntups = PQntuples(res);
8789         *numTSConfigs = ntups;
8790
8791         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8792
8793         i_tableoid = PQfnumber(res, "tableoid");
8794         i_oid = PQfnumber(res, "oid");
8795         i_cfgname = PQfnumber(res, "cfgname");
8796         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8797         i_rolname = PQfnumber(res, "rolname");
8798         i_cfgparser = PQfnumber(res, "cfgparser");
8799
8800         for (i = 0; i < ntups; i++)
8801         {
8802                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8803                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8804                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8805                 AssignDumpId(&cfginfo[i].dobj);
8806                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8807                 cfginfo[i].dobj.namespace =
8808                         findNamespace(fout,
8809                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8810                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8811                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8812
8813                 /* Decide whether we want to dump it */
8814                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8815
8816                 /* Text Search Configurations do not currently have ACLs. */
8817                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8818         }
8819
8820         PQclear(res);
8821
8822         destroyPQExpBuffer(query);
8823
8824         return cfginfo;
8825 }
8826
8827 /*
8828  * getForeignDataWrappers:
8829  *        read all foreign-data wrappers in the system catalogs and return
8830  *        them in the FdwInfo* structure
8831  *
8832  *      numForeignDataWrappers is set to the number of fdws read in
8833  */
8834 FdwInfo *
8835 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8836 {
8837         DumpOptions *dopt = fout->dopt;
8838         PGresult   *res;
8839         int                     ntups;
8840         int                     i;
8841         PQExpBuffer query;
8842         FdwInfo    *fdwinfo;
8843         int                     i_tableoid;
8844         int                     i_oid;
8845         int                     i_fdwname;
8846         int                     i_rolname;
8847         int                     i_fdwhandler;
8848         int                     i_fdwvalidator;
8849         int                     i_fdwacl;
8850         int                     i_rfdwacl;
8851         int                     i_initfdwacl;
8852         int                     i_initrfdwacl;
8853         int                     i_fdwoptions;
8854
8855         /* Before 8.4, there are no foreign-data wrappers */
8856         if (fout->remoteVersion < 80400)
8857         {
8858                 *numForeignDataWrappers = 0;
8859                 return NULL;
8860         }
8861
8862         query = createPQExpBuffer();
8863
8864         if (fout->remoteVersion >= 90600)
8865         {
8866                 PQExpBuffer acl_subquery = createPQExpBuffer();
8867                 PQExpBuffer racl_subquery = createPQExpBuffer();
8868                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8869                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8870
8871                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8872                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8873                                                 dopt->binary_upgrade);
8874
8875                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8876                                                   "(%s f.fdwowner) AS rolname, "
8877                                                   "f.fdwhandler::pg_catalog.regproc, "
8878                                                   "f.fdwvalidator::pg_catalog.regproc, "
8879                                                   "%s AS fdwacl, "
8880                                                   "%s AS rfdwacl, "
8881                                                   "%s AS initfdwacl, "
8882                                                   "%s AS initrfdwacl, "
8883                                                   "array_to_string(ARRAY("
8884                                                   "SELECT quote_ident(option_name) || ' ' || "
8885                                                   "quote_literal(option_value) "
8886                                                   "FROM pg_options_to_table(f.fdwoptions) "
8887                                                   "ORDER BY option_name"
8888                                                   "), E',\n    ') AS fdwoptions "
8889                                                   "FROM pg_foreign_data_wrapper f "
8890                                                   "LEFT JOIN pg_init_privs pip ON "
8891                                                   "(f.oid = pip.objoid "
8892                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8893                                                   "AND pip.objsubid = 0) ",
8894                                                   username_subquery,
8895                                                   acl_subquery->data,
8896                                                   racl_subquery->data,
8897                                                   initacl_subquery->data,
8898                                                   initracl_subquery->data);
8899
8900                 destroyPQExpBuffer(acl_subquery);
8901                 destroyPQExpBuffer(racl_subquery);
8902                 destroyPQExpBuffer(initacl_subquery);
8903                 destroyPQExpBuffer(initracl_subquery);
8904         }
8905         else if (fout->remoteVersion >= 90100)
8906         {
8907                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8908                                                   "(%s fdwowner) AS rolname, "
8909                                                   "fdwhandler::pg_catalog.regproc, "
8910                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8911                                                   "NULL as rfdwacl, "
8912                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8913                                                   "array_to_string(ARRAY("
8914                                                   "SELECT quote_ident(option_name) || ' ' || "
8915                                                   "quote_literal(option_value) "
8916                                                   "FROM pg_options_to_table(fdwoptions) "
8917                                                   "ORDER BY option_name"
8918                                                   "), E',\n    ') AS fdwoptions "
8919                                                   "FROM pg_foreign_data_wrapper",
8920                                                   username_subquery);
8921         }
8922         else
8923         {
8924                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8925                                                   "(%s fdwowner) AS rolname, "
8926                                                   "'-' AS fdwhandler, "
8927                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8928                                                   "NULL as rfdwacl, "
8929                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8930                                                   "array_to_string(ARRAY("
8931                                                   "SELECT quote_ident(option_name) || ' ' || "
8932                                                   "quote_literal(option_value) "
8933                                                   "FROM pg_options_to_table(fdwoptions) "
8934                                                   "ORDER BY option_name"
8935                                                   "), E',\n    ') AS fdwoptions "
8936                                                   "FROM pg_foreign_data_wrapper",
8937                                                   username_subquery);
8938         }
8939
8940         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8941
8942         ntups = PQntuples(res);
8943         *numForeignDataWrappers = ntups;
8944
8945         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
8946
8947         i_tableoid = PQfnumber(res, "tableoid");
8948         i_oid = PQfnumber(res, "oid");
8949         i_fdwname = PQfnumber(res, "fdwname");
8950         i_rolname = PQfnumber(res, "rolname");
8951         i_fdwhandler = PQfnumber(res, "fdwhandler");
8952         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
8953         i_fdwacl = PQfnumber(res, "fdwacl");
8954         i_rfdwacl = PQfnumber(res, "rfdwacl");
8955         i_initfdwacl = PQfnumber(res, "initfdwacl");
8956         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
8957         i_fdwoptions = PQfnumber(res, "fdwoptions");
8958
8959         for (i = 0; i < ntups; i++)
8960         {
8961                 fdwinfo[i].dobj.objType = DO_FDW;
8962                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8963                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8964                 AssignDumpId(&fdwinfo[i].dobj);
8965                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
8966                 fdwinfo[i].dobj.namespace = NULL;
8967                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8968                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
8969                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
8970                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
8971                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
8972                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
8973                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
8974                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
8975
8976                 /* Decide whether we want to dump it */
8977                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
8978
8979                 /* Do not try to dump ACL if no ACL exists. */
8980                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
8981                         PQgetisnull(res, i, i_initfdwacl) &&
8982                         PQgetisnull(res, i, i_initrfdwacl))
8983                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8984         }
8985
8986         PQclear(res);
8987
8988         destroyPQExpBuffer(query);
8989
8990         return fdwinfo;
8991 }
8992
8993 /*
8994  * getForeignServers:
8995  *        read all foreign servers in the system catalogs and return
8996  *        them in the ForeignServerInfo * structure
8997  *
8998  *      numForeignServers is set to the number of servers read in
8999  */
9000 ForeignServerInfo *
9001 getForeignServers(Archive *fout, int *numForeignServers)
9002 {
9003         DumpOptions *dopt = fout->dopt;
9004         PGresult   *res;
9005         int                     ntups;
9006         int                     i;
9007         PQExpBuffer query;
9008         ForeignServerInfo *srvinfo;
9009         int                     i_tableoid;
9010         int                     i_oid;
9011         int                     i_srvname;
9012         int                     i_rolname;
9013         int                     i_srvfdw;
9014         int                     i_srvtype;
9015         int                     i_srvversion;
9016         int                     i_srvacl;
9017         int                     i_rsrvacl;
9018         int                     i_initsrvacl;
9019         int                     i_initrsrvacl;
9020         int                     i_srvoptions;
9021
9022         /* Before 8.4, there are no foreign servers */
9023         if (fout->remoteVersion < 80400)
9024         {
9025                 *numForeignServers = 0;
9026                 return NULL;
9027         }
9028
9029         query = createPQExpBuffer();
9030
9031         if (fout->remoteVersion >= 90600)
9032         {
9033                 PQExpBuffer acl_subquery = createPQExpBuffer();
9034                 PQExpBuffer racl_subquery = createPQExpBuffer();
9035                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9036                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9037
9038                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9039                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9040                                                 dopt->binary_upgrade);
9041
9042                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9043                                                   "(%s f.srvowner) AS rolname, "
9044                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9045                                                   "%s AS srvacl, "
9046                                                   "%s AS rsrvacl, "
9047                                                   "%s AS initsrvacl, "
9048                                                   "%s AS initrsrvacl, "
9049                                                   "array_to_string(ARRAY("
9050                                                   "SELECT quote_ident(option_name) || ' ' || "
9051                                                   "quote_literal(option_value) "
9052                                                   "FROM pg_options_to_table(f.srvoptions) "
9053                                                   "ORDER BY option_name"
9054                                                   "), E',\n    ') AS srvoptions "
9055                                                   "FROM pg_foreign_server f "
9056                                                   "LEFT JOIN pg_init_privs pip "
9057                                                   "ON (f.oid = pip.objoid "
9058                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9059                                                   "AND pip.objsubid = 0) ",
9060                                                   username_subquery,
9061                                                   acl_subquery->data,
9062                                                   racl_subquery->data,
9063                                                   initacl_subquery->data,
9064                                                   initracl_subquery->data);
9065
9066                 destroyPQExpBuffer(acl_subquery);
9067                 destroyPQExpBuffer(racl_subquery);
9068                 destroyPQExpBuffer(initacl_subquery);
9069                 destroyPQExpBuffer(initracl_subquery);
9070         }
9071         else
9072         {
9073                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9074                                                   "(%s srvowner) AS rolname, "
9075                                                   "srvfdw, srvtype, srvversion, srvacl, "
9076                                                   "NULL AS rsrvacl, "
9077                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9078                                                   "array_to_string(ARRAY("
9079                                                   "SELECT quote_ident(option_name) || ' ' || "
9080                                                   "quote_literal(option_value) "
9081                                                   "FROM pg_options_to_table(srvoptions) "
9082                                                   "ORDER BY option_name"
9083                                                   "), E',\n    ') AS srvoptions "
9084                                                   "FROM pg_foreign_server",
9085                                                   username_subquery);
9086         }
9087
9088         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9089
9090         ntups = PQntuples(res);
9091         *numForeignServers = ntups;
9092
9093         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9094
9095         i_tableoid = PQfnumber(res, "tableoid");
9096         i_oid = PQfnumber(res, "oid");
9097         i_srvname = PQfnumber(res, "srvname");
9098         i_rolname = PQfnumber(res, "rolname");
9099         i_srvfdw = PQfnumber(res, "srvfdw");
9100         i_srvtype = PQfnumber(res, "srvtype");
9101         i_srvversion = PQfnumber(res, "srvversion");
9102         i_srvacl = PQfnumber(res, "srvacl");
9103         i_rsrvacl = PQfnumber(res, "rsrvacl");
9104         i_initsrvacl = PQfnumber(res, "initsrvacl");
9105         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9106         i_srvoptions = PQfnumber(res, "srvoptions");
9107
9108         for (i = 0; i < ntups; i++)
9109         {
9110                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9111                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9112                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9113                 AssignDumpId(&srvinfo[i].dobj);
9114                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9115                 srvinfo[i].dobj.namespace = NULL;
9116                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9117                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9118                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9119                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9120                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9121                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9122                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9123                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9124                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9125
9126                 /* Decide whether we want to dump it */
9127                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9128
9129                 /* Do not try to dump ACL if no ACL exists. */
9130                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9131                         PQgetisnull(res, i, i_initsrvacl) &&
9132                         PQgetisnull(res, i, i_initrsrvacl))
9133                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9134         }
9135
9136         PQclear(res);
9137
9138         destroyPQExpBuffer(query);
9139
9140         return srvinfo;
9141 }
9142
9143 /*
9144  * getDefaultACLs:
9145  *        read all default ACL information in the system catalogs and return
9146  *        them in the DefaultACLInfo structure
9147  *
9148  *      numDefaultACLs is set to the number of ACLs read in
9149  */
9150 DefaultACLInfo *
9151 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9152 {
9153         DumpOptions *dopt = fout->dopt;
9154         DefaultACLInfo *daclinfo;
9155         PQExpBuffer query;
9156         PGresult   *res;
9157         int                     i_oid;
9158         int                     i_tableoid;
9159         int                     i_defaclrole;
9160         int                     i_defaclnamespace;
9161         int                     i_defaclobjtype;
9162         int                     i_defaclacl;
9163         int                     i_rdefaclacl;
9164         int                     i_initdefaclacl;
9165         int                     i_initrdefaclacl;
9166         int                     i,
9167                                 ntups;
9168
9169         if (fout->remoteVersion < 90000)
9170         {
9171                 *numDefaultACLs = 0;
9172                 return NULL;
9173         }
9174
9175         query = createPQExpBuffer();
9176
9177         if (fout->remoteVersion >= 90600)
9178         {
9179                 PQExpBuffer acl_subquery = createPQExpBuffer();
9180                 PQExpBuffer racl_subquery = createPQExpBuffer();
9181                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9182                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9183
9184                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9185                                                 initracl_subquery, "defaclacl", "defaclrole",
9186                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9187                                                 dopt->binary_upgrade);
9188
9189                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9190                                                   "(%s d.defaclrole) AS defaclrole, "
9191                                                   "d.defaclnamespace, "
9192                                                   "d.defaclobjtype, "
9193                                                   "%s AS defaclacl, "
9194                                                   "%s AS rdefaclacl, "
9195                                                   "%s AS initdefaclacl, "
9196                                                   "%s AS initrdefaclacl "
9197                                                   "FROM pg_default_acl d "
9198                                                   "LEFT JOIN pg_init_privs pip ON "
9199                                                   "(d.oid = pip.objoid "
9200                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9201                                                   "AND pip.objsubid = 0) ",
9202                                                   username_subquery,
9203                                                   acl_subquery->data,
9204                                                   racl_subquery->data,
9205                                                   initacl_subquery->data,
9206                                                   initracl_subquery->data);
9207         }
9208         else
9209         {
9210                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9211                                                   "(%s defaclrole) AS defaclrole, "
9212                                                   "defaclnamespace, "
9213                                                   "defaclobjtype, "
9214                                                   "defaclacl, "
9215                                                   "NULL AS rdefaclacl, "
9216                                                   "NULL AS initdefaclacl, "
9217                                                   "NULL AS initrdefaclacl "
9218                                                   "FROM pg_default_acl",
9219                                                   username_subquery);
9220         }
9221
9222         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9223
9224         ntups = PQntuples(res);
9225         *numDefaultACLs = ntups;
9226
9227         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9228
9229         i_oid = PQfnumber(res, "oid");
9230         i_tableoid = PQfnumber(res, "tableoid");
9231         i_defaclrole = PQfnumber(res, "defaclrole");
9232         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9233         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9234         i_defaclacl = PQfnumber(res, "defaclacl");
9235         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9236         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9237         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9238
9239         for (i = 0; i < ntups; i++)
9240         {
9241                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9242
9243                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9244                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9245                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9246                 AssignDumpId(&daclinfo[i].dobj);
9247                 /* cheesy ... is it worth coming up with a better object name? */
9248                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9249
9250                 if (nspid != InvalidOid)
9251                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9252                 else
9253                         daclinfo[i].dobj.namespace = NULL;
9254
9255                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9256                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9257                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9258                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9259                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9260                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9261
9262                 /* Decide whether we want to dump it */
9263                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9264         }
9265
9266         PQclear(res);
9267
9268         destroyPQExpBuffer(query);
9269
9270         return daclinfo;
9271 }
9272
9273 /*
9274  * dumpComment --
9275  *
9276  * This routine is used to dump any comments associated with the
9277  * object handed to this routine. The routine takes the object type
9278  * and object name (ready to print, except for schema decoration), plus
9279  * the namespace and owner of the object (for labeling the ArchiveEntry),
9280  * plus catalog ID and subid which are the lookup key for pg_description,
9281  * plus the dump ID for the object (for setting a dependency).
9282  * If a matching pg_description entry is found, it is dumped.
9283  *
9284  * Note: in some cases, such as comments for triggers and rules, the "type"
9285  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9286  * but it doesn't seem worth complicating the API for all callers to make
9287  * it cleaner.
9288  *
9289  * Note: although this routine takes a dumpId for dependency purposes,
9290  * that purpose is just to mark the dependency in the emitted dump file
9291  * for possible future use by pg_restore.  We do NOT use it for determining
9292  * ordering of the comment in the dump file, because this routine is called
9293  * after dependency sorting occurs.  This routine should be called just after
9294  * calling ArchiveEntry() for the specified object.
9295  */
9296 static void
9297 dumpComment(Archive *fout, const char *type, const char *name,
9298                         const char *namespace, const char *owner,
9299                         CatalogId catalogId, int subid, DumpId dumpId)
9300 {
9301         DumpOptions *dopt = fout->dopt;
9302         CommentItem *comments;
9303         int                     ncomments;
9304
9305         /* do nothing, if --no-comments is supplied */
9306         if (dopt->no_comments)
9307                 return;
9308
9309         /* Comments are schema not data ... except blob comments are data */
9310         if (strcmp(type, "LARGE OBJECT") != 0)
9311         {
9312                 if (dopt->dataOnly)
9313                         return;
9314         }
9315         else
9316         {
9317                 /* We do dump blob comments in binary-upgrade mode */
9318                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9319                         return;
9320         }
9321
9322         /* Search for comments associated with catalogId, using table */
9323         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9324                                                          &comments);
9325
9326         /* Is there one matching the subid? */
9327         while (ncomments > 0)
9328         {
9329                 if (comments->objsubid == subid)
9330                         break;
9331                 comments++;
9332                 ncomments--;
9333         }
9334
9335         /* If a comment exists, build COMMENT ON statement */
9336         if (ncomments > 0)
9337         {
9338                 PQExpBuffer query = createPQExpBuffer();
9339                 PQExpBuffer tag = createPQExpBuffer();
9340
9341                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9342                 if (namespace && *namespace)
9343                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9344                 appendPQExpBuffer(query, "%s IS ", name);
9345                 appendStringLiteralAH(query, comments->descr, fout);
9346                 appendPQExpBufferStr(query, ";\n");
9347
9348                 appendPQExpBuffer(tag, "%s %s", type, name);
9349
9350                 /*
9351                  * We mark comments as SECTION_NONE because they really belong in the
9352                  * same section as their parent, whether that is pre-data or
9353                  * post-data.
9354                  */
9355                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9356                                          tag->data, namespace, NULL, owner,
9357                                          false, "COMMENT", SECTION_NONE,
9358                                          query->data, "", NULL,
9359                                          &(dumpId), 1,
9360                                          NULL, NULL);
9361
9362                 destroyPQExpBuffer(query);
9363                 destroyPQExpBuffer(tag);
9364         }
9365 }
9366
9367 /*
9368  * dumpTableComment --
9369  *
9370  * As above, but dump comments for both the specified table (or view)
9371  * and its columns.
9372  */
9373 static void
9374 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9375                                  const char *reltypename)
9376 {
9377         DumpOptions *dopt = fout->dopt;
9378         CommentItem *comments;
9379         int                     ncomments;
9380         PQExpBuffer query;
9381         PQExpBuffer tag;
9382
9383         /* do nothing, if --no-comments is supplied */
9384         if (dopt->no_comments)
9385                 return;
9386
9387         /* Comments are SCHEMA not data */
9388         if (dopt->dataOnly)
9389                 return;
9390
9391         /* Search for comments associated with relation, using table */
9392         ncomments = findComments(fout,
9393                                                          tbinfo->dobj.catId.tableoid,
9394                                                          tbinfo->dobj.catId.oid,
9395                                                          &comments);
9396
9397         /* If comments exist, build COMMENT ON statements */
9398         if (ncomments <= 0)
9399                 return;
9400
9401         query = createPQExpBuffer();
9402         tag = createPQExpBuffer();
9403
9404         while (ncomments > 0)
9405         {
9406                 const char *descr = comments->descr;
9407                 int                     objsubid = comments->objsubid;
9408
9409                 if (objsubid == 0)
9410                 {
9411                         resetPQExpBuffer(tag);
9412                         appendPQExpBuffer(tag, "%s %s", reltypename,
9413                                                           fmtId(tbinfo->dobj.name));
9414
9415                         resetPQExpBuffer(query);
9416                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9417                                                           fmtQualifiedDumpable(tbinfo));
9418                         appendStringLiteralAH(query, descr, fout);
9419                         appendPQExpBufferStr(query, ";\n");
9420
9421                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9422                                                  tag->data,
9423                                                  tbinfo->dobj.namespace->dobj.name,
9424                                                  NULL, tbinfo->rolname,
9425                                                  false, "COMMENT", SECTION_NONE,
9426                                                  query->data, "", NULL,
9427                                                  &(tbinfo->dobj.dumpId), 1,
9428                                                  NULL, NULL);
9429                 }
9430                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9431                 {
9432                         resetPQExpBuffer(tag);
9433                         appendPQExpBuffer(tag, "COLUMN %s.",
9434                                                           fmtId(tbinfo->dobj.name));
9435                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9436
9437                         resetPQExpBuffer(query);
9438                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9439                                                           fmtQualifiedDumpable(tbinfo));
9440                         appendPQExpBuffer(query, "%s IS ",
9441                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9442                         appendStringLiteralAH(query, descr, fout);
9443                         appendPQExpBufferStr(query, ";\n");
9444
9445                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9446                                                  tag->data,
9447                                                  tbinfo->dobj.namespace->dobj.name,
9448                                                  NULL, tbinfo->rolname,
9449                                                  false, "COMMENT", SECTION_NONE,
9450                                                  query->data, "", NULL,
9451                                                  &(tbinfo->dobj.dumpId), 1,
9452                                                  NULL, NULL);
9453                 }
9454
9455                 comments++;
9456                 ncomments--;
9457         }
9458
9459         destroyPQExpBuffer(query);
9460         destroyPQExpBuffer(tag);
9461 }
9462
9463 /*
9464  * findComments --
9465  *
9466  * Find the comment(s), if any, associated with the given object.  All the
9467  * objsubid values associated with the given classoid/objoid are found with
9468  * one search.
9469  */
9470 static int
9471 findComments(Archive *fout, Oid classoid, Oid objoid,
9472                          CommentItem **items)
9473 {
9474         /* static storage for table of comments */
9475         static CommentItem *comments = NULL;
9476         static int      ncomments = -1;
9477
9478         CommentItem *middle = NULL;
9479         CommentItem *low;
9480         CommentItem *high;
9481         int                     nmatch;
9482
9483         /* Get comments if we didn't already */
9484         if (ncomments < 0)
9485                 ncomments = collectComments(fout, &comments);
9486
9487         /*
9488          * Do binary search to find some item matching the object.
9489          */
9490         low = &comments[0];
9491         high = &comments[ncomments - 1];
9492         while (low <= high)
9493         {
9494                 middle = low + (high - low) / 2;
9495
9496                 if (classoid < middle->classoid)
9497                         high = middle - 1;
9498                 else if (classoid > middle->classoid)
9499                         low = middle + 1;
9500                 else if (objoid < middle->objoid)
9501                         high = middle - 1;
9502                 else if (objoid > middle->objoid)
9503                         low = middle + 1;
9504                 else
9505                         break;                          /* found a match */
9506         }
9507
9508         if (low > high)                         /* no matches */
9509         {
9510                 *items = NULL;
9511                 return 0;
9512         }
9513
9514         /*
9515          * Now determine how many items match the object.  The search loop
9516          * invariant still holds: only items between low and high inclusive could
9517          * match.
9518          */
9519         nmatch = 1;
9520         while (middle > low)
9521         {
9522                 if (classoid != middle[-1].classoid ||
9523                         objoid != middle[-1].objoid)
9524                         break;
9525                 middle--;
9526                 nmatch++;
9527         }
9528
9529         *items = middle;
9530
9531         middle += nmatch;
9532         while (middle <= high)
9533         {
9534                 if (classoid != middle->classoid ||
9535                         objoid != middle->objoid)
9536                         break;
9537                 middle++;
9538                 nmatch++;
9539         }
9540
9541         return nmatch;
9542 }
9543
9544 /*
9545  * collectComments --
9546  *
9547  * Construct a table of all comments available for database objects.
9548  * We used to do per-object queries for the comments, but it's much faster
9549  * to pull them all over at once, and on most databases the memory cost
9550  * isn't high.
9551  *
9552  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9553  */
9554 static int
9555 collectComments(Archive *fout, CommentItem **items)
9556 {
9557         PGresult   *res;
9558         PQExpBuffer query;
9559         int                     i_description;
9560         int                     i_classoid;
9561         int                     i_objoid;
9562         int                     i_objsubid;
9563         int                     ntups;
9564         int                     i;
9565         CommentItem *comments;
9566
9567         query = createPQExpBuffer();
9568
9569         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9570                                                  "FROM pg_catalog.pg_description "
9571                                                  "ORDER BY classoid, objoid, objsubid");
9572
9573         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9574
9575         /* Construct lookup table containing OIDs in numeric form */
9576
9577         i_description = PQfnumber(res, "description");
9578         i_classoid = PQfnumber(res, "classoid");
9579         i_objoid = PQfnumber(res, "objoid");
9580         i_objsubid = PQfnumber(res, "objsubid");
9581
9582         ntups = PQntuples(res);
9583
9584         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9585
9586         for (i = 0; i < ntups; i++)
9587         {
9588                 comments[i].descr = PQgetvalue(res, i, i_description);
9589                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9590                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9591                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9592         }
9593
9594         /* Do NOT free the PGresult since we are keeping pointers into it */
9595         destroyPQExpBuffer(query);
9596
9597         *items = comments;
9598         return ntups;
9599 }
9600
9601 /*
9602  * dumpDumpableObject
9603  *
9604  * This routine and its subsidiaries are responsible for creating
9605  * ArchiveEntries (TOC objects) for each object to be dumped.
9606  */
9607 static void
9608 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9609 {
9610         switch (dobj->objType)
9611         {
9612                 case DO_NAMESPACE:
9613                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9614                         break;
9615                 case DO_EXTENSION:
9616                         dumpExtension(fout, (ExtensionInfo *) dobj);
9617                         break;
9618                 case DO_TYPE:
9619                         dumpType(fout, (TypeInfo *) dobj);
9620                         break;
9621                 case DO_SHELL_TYPE:
9622                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9623                         break;
9624                 case DO_FUNC:
9625                         dumpFunc(fout, (FuncInfo *) dobj);
9626                         break;
9627                 case DO_AGG:
9628                         dumpAgg(fout, (AggInfo *) dobj);
9629                         break;
9630                 case DO_OPERATOR:
9631                         dumpOpr(fout, (OprInfo *) dobj);
9632                         break;
9633                 case DO_ACCESS_METHOD:
9634                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9635                         break;
9636                 case DO_OPCLASS:
9637                         dumpOpclass(fout, (OpclassInfo *) dobj);
9638                         break;
9639                 case DO_OPFAMILY:
9640                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9641                         break;
9642                 case DO_COLLATION:
9643                         dumpCollation(fout, (CollInfo *) dobj);
9644                         break;
9645                 case DO_CONVERSION:
9646                         dumpConversion(fout, (ConvInfo *) dobj);
9647                         break;
9648                 case DO_TABLE:
9649                         dumpTable(fout, (TableInfo *) dobj);
9650                         break;
9651                 case DO_ATTRDEF:
9652                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9653                         break;
9654                 case DO_INDEX:
9655                         dumpIndex(fout, (IndxInfo *) dobj);
9656                         break;
9657                 case DO_INDEX_ATTACH:
9658                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9659                         break;
9660                 case DO_STATSEXT:
9661                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9662                         break;
9663                 case DO_REFRESH_MATVIEW:
9664                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9665                         break;
9666                 case DO_RULE:
9667                         dumpRule(fout, (RuleInfo *) dobj);
9668                         break;
9669                 case DO_TRIGGER:
9670                         dumpTrigger(fout, (TriggerInfo *) dobj);
9671                         break;
9672                 case DO_EVENT_TRIGGER:
9673                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9674                         break;
9675                 case DO_CONSTRAINT:
9676                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9677                         break;
9678                 case DO_FK_CONSTRAINT:
9679                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9680                         break;
9681                 case DO_PROCLANG:
9682                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9683                         break;
9684                 case DO_CAST:
9685                         dumpCast(fout, (CastInfo *) dobj);
9686                         break;
9687                 case DO_TRANSFORM:
9688                         dumpTransform(fout, (TransformInfo *) dobj);
9689                         break;
9690                 case DO_SEQUENCE_SET:
9691                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9692                         break;
9693                 case DO_TABLE_DATA:
9694                         dumpTableData(fout, (TableDataInfo *) dobj);
9695                         break;
9696                 case DO_DUMMY_TYPE:
9697                         /* table rowtypes and array types are never dumped separately */
9698                         break;
9699                 case DO_TSPARSER:
9700                         dumpTSParser(fout, (TSParserInfo *) dobj);
9701                         break;
9702                 case DO_TSDICT:
9703                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9704                         break;
9705                 case DO_TSTEMPLATE:
9706                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9707                         break;
9708                 case DO_TSCONFIG:
9709                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9710                         break;
9711                 case DO_FDW:
9712                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9713                         break;
9714                 case DO_FOREIGN_SERVER:
9715                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9716                         break;
9717                 case DO_DEFAULT_ACL:
9718                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9719                         break;
9720                 case DO_BLOB:
9721                         dumpBlob(fout, (BlobInfo *) dobj);
9722                         break;
9723                 case DO_BLOB_DATA:
9724                         if (dobj->dump & DUMP_COMPONENT_DATA)
9725                                 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9726                                                          dobj->name, NULL, NULL, "",
9727                                                          false, "BLOBS", SECTION_DATA,
9728                                                          "", "", NULL,
9729                                                          NULL, 0,
9730                                                          dumpBlobs, NULL);
9731                         break;
9732                 case DO_POLICY:
9733                         dumpPolicy(fout, (PolicyInfo *) dobj);
9734                         break;
9735                 case DO_PUBLICATION:
9736                         dumpPublication(fout, (PublicationInfo *) dobj);
9737                         break;
9738                 case DO_PUBLICATION_REL:
9739                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9740                         break;
9741                 case DO_SUBSCRIPTION:
9742                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9743                         break;
9744                 case DO_PRE_DATA_BOUNDARY:
9745                 case DO_POST_DATA_BOUNDARY:
9746                         /* never dumped, nothing to do */
9747                         break;
9748         }
9749 }
9750
9751 /*
9752  * dumpNamespace
9753  *        writes out to fout the queries to recreate a user-defined namespace
9754  */
9755 static void
9756 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9757 {
9758         DumpOptions *dopt = fout->dopt;
9759         PQExpBuffer q;
9760         PQExpBuffer delq;
9761         char       *qnspname;
9762
9763         /* Skip if not to be dumped */
9764         if (!nspinfo->dobj.dump || dopt->dataOnly)
9765                 return;
9766
9767         q = createPQExpBuffer();
9768         delq = createPQExpBuffer();
9769
9770         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9771
9772         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9773
9774         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9775
9776         if (dopt->binary_upgrade)
9777                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9778                                                                                 "SCHEMA", qnspname, NULL);
9779
9780         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9781                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9782                                          nspinfo->dobj.name,
9783                                          NULL, NULL,
9784                                          nspinfo->rolname,
9785                                          false, "SCHEMA", SECTION_PRE_DATA,
9786                                          q->data, delq->data, NULL,
9787                                          NULL, 0,
9788                                          NULL, NULL);
9789
9790         /* Dump Schema Comments and Security Labels */
9791         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9792                 dumpComment(fout, "SCHEMA", qnspname,
9793                                         NULL, nspinfo->rolname,
9794                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9795
9796         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9797                 dumpSecLabel(fout, "SCHEMA", qnspname,
9798                                          NULL, nspinfo->rolname,
9799                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9800
9801         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9802                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9803                                 qnspname, NULL, NULL,
9804                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9805                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9806
9807         free(qnspname);
9808
9809         destroyPQExpBuffer(q);
9810         destroyPQExpBuffer(delq);
9811 }
9812
9813 /*
9814  * dumpExtension
9815  *        writes out to fout the queries to recreate an extension
9816  */
9817 static void
9818 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9819 {
9820         DumpOptions *dopt = fout->dopt;
9821         PQExpBuffer q;
9822         PQExpBuffer delq;
9823         char       *qextname;
9824
9825         /* Skip if not to be dumped */
9826         if (!extinfo->dobj.dump || dopt->dataOnly)
9827                 return;
9828
9829         q = createPQExpBuffer();
9830         delq = createPQExpBuffer();
9831
9832         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9833
9834         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9835
9836         if (!dopt->binary_upgrade)
9837         {
9838                 /*
9839                  * In a regular dump, we simply create the extension, intentionally
9840                  * not specifying a version, so that the destination installation's
9841                  * default version is used.
9842                  *
9843                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9844                  * types; but there are various scenarios in which it's convenient to
9845                  * manually create the desired extension before restoring, so we
9846                  * prefer to allow it to exist already.
9847                  */
9848                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9849                                                   qextname, fmtId(extinfo->namespace));
9850         }
9851         else
9852         {
9853                 /*
9854                  * In binary-upgrade mode, it's critical to reproduce the state of the
9855                  * database exactly, so our procedure is to create an empty extension,
9856                  * restore all the contained objects normally, and add them to the
9857                  * extension one by one.  This function performs just the first of
9858                  * those steps.  binary_upgrade_extension_member() takes care of
9859                  * adding member objects as they're created.
9860                  */
9861                 int                     i;
9862                 int                     n;
9863
9864                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9865
9866                 /*
9867                  * We unconditionally create the extension, so we must drop it if it
9868                  * exists.  This could happen if the user deleted 'plpgsql' and then
9869                  * readded it, causing its oid to be greater than g_last_builtin_oid.
9870                  */
9871                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9872
9873                 appendPQExpBufferStr(q,
9874                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9875                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
9876                 appendPQExpBufferStr(q, ", ");
9877                 appendStringLiteralAH(q, extinfo->namespace, fout);
9878                 appendPQExpBufferStr(q, ", ");
9879                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9880                 appendStringLiteralAH(q, extinfo->extversion, fout);
9881                 appendPQExpBufferStr(q, ", ");
9882
9883                 /*
9884                  * Note that we're pushing extconfig (an OID array) back into
9885                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
9886                  * preserved in binary upgrade.
9887                  */
9888                 if (strlen(extinfo->extconfig) > 2)
9889                         appendStringLiteralAH(q, extinfo->extconfig, fout);
9890                 else
9891                         appendPQExpBufferStr(q, "NULL");
9892                 appendPQExpBufferStr(q, ", ");
9893                 if (strlen(extinfo->extcondition) > 2)
9894                         appendStringLiteralAH(q, extinfo->extcondition, fout);
9895                 else
9896                         appendPQExpBufferStr(q, "NULL");
9897                 appendPQExpBufferStr(q, ", ");
9898                 appendPQExpBufferStr(q, "ARRAY[");
9899                 n = 0;
9900                 for (i = 0; i < extinfo->dobj.nDeps; i++)
9901                 {
9902                         DumpableObject *extobj;
9903
9904                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9905                         if (extobj && extobj->objType == DO_EXTENSION)
9906                         {
9907                                 if (n++ > 0)
9908                                         appendPQExpBufferChar(q, ',');
9909                                 appendStringLiteralAH(q, extobj->name, fout);
9910                         }
9911                 }
9912                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9913                 appendPQExpBufferStr(q, ");\n");
9914         }
9915
9916         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9917                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9918                                          extinfo->dobj.name,
9919                                          NULL, NULL,
9920                                          "",
9921                                          false, "EXTENSION", SECTION_PRE_DATA,
9922                                          q->data, delq->data, NULL,
9923                                          NULL, 0,
9924                                          NULL, NULL);
9925
9926         /* Dump Extension Comments and Security Labels */
9927         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9928                 dumpComment(fout, "EXTENSION", qextname,
9929                                         NULL, "",
9930                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9931
9932         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9933                 dumpSecLabel(fout, "EXTENSION", qextname,
9934                                          NULL, "",
9935                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9936
9937         free(qextname);
9938
9939         destroyPQExpBuffer(q);
9940         destroyPQExpBuffer(delq);
9941 }
9942
9943 /*
9944  * dumpType
9945  *        writes out to fout the queries to recreate a user-defined type
9946  */
9947 static void
9948 dumpType(Archive *fout, TypeInfo *tyinfo)
9949 {
9950         DumpOptions *dopt = fout->dopt;
9951
9952         /* Skip if not to be dumped */
9953         if (!tyinfo->dobj.dump || dopt->dataOnly)
9954                 return;
9955
9956         /* Dump out in proper style */
9957         if (tyinfo->typtype == TYPTYPE_BASE)
9958                 dumpBaseType(fout, tyinfo);
9959         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
9960                 dumpDomain(fout, tyinfo);
9961         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
9962                 dumpCompositeType(fout, tyinfo);
9963         else if (tyinfo->typtype == TYPTYPE_ENUM)
9964                 dumpEnumType(fout, tyinfo);
9965         else if (tyinfo->typtype == TYPTYPE_RANGE)
9966                 dumpRangeType(fout, tyinfo);
9967         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
9968                 dumpUndefinedType(fout, tyinfo);
9969         else
9970                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
9971                                   tyinfo->dobj.name);
9972 }
9973
9974 /*
9975  * dumpEnumType
9976  *        writes out to fout the queries to recreate a user-defined enum type
9977  */
9978 static void
9979 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
9980 {
9981         DumpOptions *dopt = fout->dopt;
9982         PQExpBuffer q = createPQExpBuffer();
9983         PQExpBuffer delq = createPQExpBuffer();
9984         PQExpBuffer query = createPQExpBuffer();
9985         PGresult   *res;
9986         int                     num,
9987                                 i;
9988         Oid                     enum_oid;
9989         char       *qtypname;
9990         char       *qualtypname;
9991         char       *label;
9992
9993         if (fout->remoteVersion >= 90100)
9994                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
9995                                                   "FROM pg_catalog.pg_enum "
9996                                                   "WHERE enumtypid = '%u'"
9997                                                   "ORDER BY enumsortorder",
9998                                                   tyinfo->dobj.catId.oid);
9999         else
10000                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10001                                                   "FROM pg_catalog.pg_enum "
10002                                                   "WHERE enumtypid = '%u'"
10003                                                   "ORDER BY oid",
10004                                                   tyinfo->dobj.catId.oid);
10005
10006         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10007
10008         num = PQntuples(res);
10009
10010         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10011         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10012
10013         /*
10014          * CASCADE shouldn't be required here as for normal types since the I/O
10015          * functions are generic and do not get dropped.
10016          */
10017         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10018
10019         if (dopt->binary_upgrade)
10020                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10021                                                                                                  tyinfo->dobj.catId.oid,
10022                                                                                                  false);
10023
10024         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10025                                           qualtypname);
10026
10027         if (!dopt->binary_upgrade)
10028         {
10029                 /* Labels with server-assigned oids */
10030                 for (i = 0; i < num; i++)
10031                 {
10032                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10033                         if (i > 0)
10034                                 appendPQExpBufferChar(q, ',');
10035                         appendPQExpBufferStr(q, "\n    ");
10036                         appendStringLiteralAH(q, label, fout);
10037                 }
10038         }
10039
10040         appendPQExpBufferStr(q, "\n);\n");
10041
10042         if (dopt->binary_upgrade)
10043         {
10044                 /* Labels with dump-assigned (preserved) oids */
10045                 for (i = 0; i < num; i++)
10046                 {
10047                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10048                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10049
10050                         if (i == 0)
10051                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10052                         appendPQExpBuffer(q,
10053                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10054                                                           enum_oid);
10055                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10056                         appendStringLiteralAH(q, label, fout);
10057                         appendPQExpBufferStr(q, ";\n\n");
10058                 }
10059         }
10060
10061         if (dopt->binary_upgrade)
10062                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10063                                                                                 "TYPE", qtypname,
10064                                                                                 tyinfo->dobj.namespace->dobj.name);
10065
10066         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10067                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10068                                          tyinfo->dobj.name,
10069                                          tyinfo->dobj.namespace->dobj.name,
10070                                          NULL,
10071                                          tyinfo->rolname, false,
10072                                          "TYPE", SECTION_PRE_DATA,
10073                                          q->data, delq->data, NULL,
10074                                          NULL, 0,
10075                                          NULL, NULL);
10076
10077         /* Dump Type Comments and Security Labels */
10078         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10079                 dumpComment(fout, "TYPE", qtypname,
10080                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10081                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10082
10083         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10084                 dumpSecLabel(fout, "TYPE", qtypname,
10085                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10086                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10087
10088         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10089                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10090                                 qtypname, NULL,
10091                                 tyinfo->dobj.namespace->dobj.name,
10092                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10093                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10094
10095         PQclear(res);
10096         destroyPQExpBuffer(q);
10097         destroyPQExpBuffer(delq);
10098         destroyPQExpBuffer(query);
10099         free(qtypname);
10100         free(qualtypname);
10101 }
10102
10103 /*
10104  * dumpRangeType
10105  *        writes out to fout the queries to recreate a user-defined range type
10106  */
10107 static void
10108 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10109 {
10110         DumpOptions *dopt = fout->dopt;
10111         PQExpBuffer q = createPQExpBuffer();
10112         PQExpBuffer delq = createPQExpBuffer();
10113         PQExpBuffer query = createPQExpBuffer();
10114         PGresult   *res;
10115         Oid                     collationOid;
10116         char       *qtypname;
10117         char       *qualtypname;
10118         char       *procname;
10119
10120         appendPQExpBuffer(query,
10121                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10122                                           "opc.opcname AS opcname, "
10123                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10124                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10125                                           "opc.opcdefault, "
10126                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10127                                           "     ELSE rngcollation END AS collation, "
10128                                           "rngcanonical, rngsubdiff "
10129                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10130                                           "     pg_catalog.pg_opclass opc "
10131                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10132                                           "rngtypid = '%u'",
10133                                           tyinfo->dobj.catId.oid);
10134
10135         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10136
10137         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10138         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10139
10140         /*
10141          * CASCADE shouldn't be required here as for normal types since the I/O
10142          * functions are generic and do not get dropped.
10143          */
10144         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10145
10146         if (dopt->binary_upgrade)
10147                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10148                                                                                                  tyinfo->dobj.catId.oid,
10149                                                                                                  false);
10150
10151         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10152                                           qualtypname);
10153
10154         appendPQExpBuffer(q, "\n    subtype = %s",
10155                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10156
10157         /* print subtype_opclass only if not default for subtype */
10158         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10159         {
10160                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10161                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10162
10163                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10164                                                   fmtId(nspname));
10165                 appendPQExpBufferStr(q, fmtId(opcname));
10166         }
10167
10168         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10169         if (OidIsValid(collationOid))
10170         {
10171                 CollInfo   *coll = findCollationByOid(collationOid);
10172
10173                 if (coll)
10174                         appendPQExpBuffer(q, ",\n    collation = %s",
10175                                                           fmtQualifiedDumpable(coll));
10176         }
10177
10178         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10179         if (strcmp(procname, "-") != 0)
10180                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10181
10182         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10183         if (strcmp(procname, "-") != 0)
10184                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10185
10186         appendPQExpBufferStr(q, "\n);\n");
10187
10188         if (dopt->binary_upgrade)
10189                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10190                                                                                 "TYPE", qtypname,
10191                                                                                 tyinfo->dobj.namespace->dobj.name);
10192
10193         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10194                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10195                                          tyinfo->dobj.name,
10196                                          tyinfo->dobj.namespace->dobj.name,
10197                                          NULL,
10198                                          tyinfo->rolname, false,
10199                                          "TYPE", SECTION_PRE_DATA,
10200                                          q->data, delq->data, NULL,
10201                                          NULL, 0,
10202                                          NULL, NULL);
10203
10204         /* Dump Type Comments and Security Labels */
10205         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10206                 dumpComment(fout, "TYPE", qtypname,
10207                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10208                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10209
10210         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10211                 dumpSecLabel(fout, "TYPE", qtypname,
10212                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10213                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10214
10215         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10216                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10217                                 qtypname, NULL,
10218                                 tyinfo->dobj.namespace->dobj.name,
10219                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10220                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10221
10222         PQclear(res);
10223         destroyPQExpBuffer(q);
10224         destroyPQExpBuffer(delq);
10225         destroyPQExpBuffer(query);
10226         free(qtypname);
10227         free(qualtypname);
10228 }
10229
10230 /*
10231  * dumpUndefinedType
10232  *        writes out to fout the queries to recreate a !typisdefined type
10233  *
10234  * This is a shell type, but we use different terminology to distinguish
10235  * this case from where we have to emit a shell type definition to break
10236  * circular dependencies.  An undefined type shouldn't ever have anything
10237  * depending on it.
10238  */
10239 static void
10240 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10241 {
10242         DumpOptions *dopt = fout->dopt;
10243         PQExpBuffer q = createPQExpBuffer();
10244         PQExpBuffer delq = createPQExpBuffer();
10245         char       *qtypname;
10246         char       *qualtypname;
10247
10248         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10249         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10250
10251         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10252
10253         if (dopt->binary_upgrade)
10254                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10255                                                                                                  tyinfo->dobj.catId.oid,
10256                                                                                                  false);
10257
10258         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10259                                           qualtypname);
10260
10261         if (dopt->binary_upgrade)
10262                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10263                                                                                 "TYPE", qtypname,
10264                                                                                 tyinfo->dobj.namespace->dobj.name);
10265
10266         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10267                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10268                                          tyinfo->dobj.name,
10269                                          tyinfo->dobj.namespace->dobj.name,
10270                                          NULL,
10271                                          tyinfo->rolname, false,
10272                                          "TYPE", SECTION_PRE_DATA,
10273                                          q->data, delq->data, NULL,
10274                                          NULL, 0,
10275                                          NULL, NULL);
10276
10277         /* Dump Type Comments and Security Labels */
10278         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10279                 dumpComment(fout, "TYPE", qtypname,
10280                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10281                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10282
10283         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10284                 dumpSecLabel(fout, "TYPE", qtypname,
10285                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10286                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10287
10288         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10289                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10290                                 qtypname, NULL,
10291                                 tyinfo->dobj.namespace->dobj.name,
10292                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10293                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10294
10295         destroyPQExpBuffer(q);
10296         destroyPQExpBuffer(delq);
10297         free(qtypname);
10298         free(qualtypname);
10299 }
10300
10301 /*
10302  * dumpBaseType
10303  *        writes out to fout the queries to recreate a user-defined base type
10304  */
10305 static void
10306 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10307 {
10308         DumpOptions *dopt = fout->dopt;
10309         PQExpBuffer q = createPQExpBuffer();
10310         PQExpBuffer delq = createPQExpBuffer();
10311         PQExpBuffer query = createPQExpBuffer();
10312         PGresult   *res;
10313         char       *qtypname;
10314         char       *qualtypname;
10315         char       *typlen;
10316         char       *typinput;
10317         char       *typoutput;
10318         char       *typreceive;
10319         char       *typsend;
10320         char       *typmodin;
10321         char       *typmodout;
10322         char       *typanalyze;
10323         Oid                     typreceiveoid;
10324         Oid                     typsendoid;
10325         Oid                     typmodinoid;
10326         Oid                     typmodoutoid;
10327         Oid                     typanalyzeoid;
10328         char       *typcategory;
10329         char       *typispreferred;
10330         char       *typdelim;
10331         char       *typbyval;
10332         char       *typalign;
10333         char       *typstorage;
10334         char       *typcollatable;
10335         char       *typdefault;
10336         bool            typdefault_is_literal = false;
10337
10338         /* Fetch type-specific details */
10339         if (fout->remoteVersion >= 90100)
10340         {
10341                 appendPQExpBuffer(query, "SELECT typlen, "
10342                                                   "typinput, typoutput, typreceive, typsend, "
10343                                                   "typmodin, typmodout, typanalyze, "
10344                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10345                                                   "typsend::pg_catalog.oid AS typsendoid, "
10346                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10347                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10348                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10349                                                   "typcategory, typispreferred, "
10350                                                   "typdelim, typbyval, typalign, typstorage, "
10351                                                   "(typcollation <> 0) AS typcollatable, "
10352                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10353                                                   "FROM pg_catalog.pg_type "
10354                                                   "WHERE oid = '%u'::pg_catalog.oid",
10355                                                   tyinfo->dobj.catId.oid);
10356         }
10357         else if (fout->remoteVersion >= 80400)
10358         {
10359                 appendPQExpBuffer(query, "SELECT typlen, "
10360                                                   "typinput, typoutput, typreceive, typsend, "
10361                                                   "typmodin, typmodout, typanalyze, "
10362                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10363                                                   "typsend::pg_catalog.oid AS typsendoid, "
10364                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10365                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10366                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10367                                                   "typcategory, typispreferred, "
10368                                                   "typdelim, typbyval, typalign, typstorage, "
10369                                                   "false AS typcollatable, "
10370                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10371                                                   "FROM pg_catalog.pg_type "
10372                                                   "WHERE oid = '%u'::pg_catalog.oid",
10373                                                   tyinfo->dobj.catId.oid);
10374         }
10375         else if (fout->remoteVersion >= 80300)
10376         {
10377                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10378                 appendPQExpBuffer(query, "SELECT typlen, "
10379                                                   "typinput, typoutput, typreceive, typsend, "
10380                                                   "typmodin, typmodout, typanalyze, "
10381                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10382                                                   "typsend::pg_catalog.oid AS typsendoid, "
10383                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10384                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10385                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10386                                                   "'U' AS typcategory, false AS typispreferred, "
10387                                                   "typdelim, typbyval, typalign, typstorage, "
10388                                                   "false AS typcollatable, "
10389                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10390                                                   "FROM pg_catalog.pg_type "
10391                                                   "WHERE oid = '%u'::pg_catalog.oid",
10392                                                   tyinfo->dobj.catId.oid);
10393         }
10394         else
10395         {
10396                 appendPQExpBuffer(query, "SELECT typlen, "
10397                                                   "typinput, typoutput, typreceive, typsend, "
10398                                                   "'-' AS typmodin, '-' AS typmodout, "
10399                                                   "typanalyze, "
10400                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10401                                                   "typsend::pg_catalog.oid AS typsendoid, "
10402                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10403                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10404                                                   "'U' AS typcategory, false AS typispreferred, "
10405                                                   "typdelim, typbyval, typalign, typstorage, "
10406                                                   "false AS typcollatable, "
10407                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10408                                                   "FROM pg_catalog.pg_type "
10409                                                   "WHERE oid = '%u'::pg_catalog.oid",
10410                                                   tyinfo->dobj.catId.oid);
10411         }
10412
10413         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10414
10415         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10416         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10417         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10418         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10419         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10420         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10421         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10422         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10423         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10424         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10425         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10426         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10427         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10428         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10429         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10430         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10431         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10432         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10433         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10434         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10435         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10436                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10437         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10438         {
10439                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10440                 typdefault_is_literal = true;   /* it needs quotes */
10441         }
10442         else
10443                 typdefault = NULL;
10444
10445         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10446         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10447
10448         /*
10449          * The reason we include CASCADE is that the circular dependency between
10450          * the type and its I/O functions makes it impossible to drop the type any
10451          * other way.
10452          */
10453         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10454
10455         /*
10456          * We might already have a shell type, but setting pg_type_oid is
10457          * harmless, and in any case we'd better set the array type OID.
10458          */
10459         if (dopt->binary_upgrade)
10460                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10461                                                                                                  tyinfo->dobj.catId.oid,
10462                                                                                                  false);
10463
10464         appendPQExpBuffer(q,
10465                                           "CREATE TYPE %s (\n"
10466                                           "    INTERNALLENGTH = %s",
10467                                           qualtypname,
10468                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10469
10470         /* regproc result is sufficiently quoted already */
10471         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10472         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10473         if (OidIsValid(typreceiveoid))
10474                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10475         if (OidIsValid(typsendoid))
10476                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10477         if (OidIsValid(typmodinoid))
10478                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10479         if (OidIsValid(typmodoutoid))
10480                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10481         if (OidIsValid(typanalyzeoid))
10482                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10483
10484         if (strcmp(typcollatable, "t") == 0)
10485                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10486
10487         if (typdefault != NULL)
10488         {
10489                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10490                 if (typdefault_is_literal)
10491                         appendStringLiteralAH(q, typdefault, fout);
10492                 else
10493                         appendPQExpBufferStr(q, typdefault);
10494         }
10495
10496         if (OidIsValid(tyinfo->typelem))
10497         {
10498                 char       *elemType;
10499
10500                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10501                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10502                 free(elemType);
10503         }
10504
10505         if (strcmp(typcategory, "U") != 0)
10506         {
10507                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10508                 appendStringLiteralAH(q, typcategory, fout);
10509         }
10510
10511         if (strcmp(typispreferred, "t") == 0)
10512                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10513
10514         if (typdelim && strcmp(typdelim, ",") != 0)
10515         {
10516                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10517                 appendStringLiteralAH(q, typdelim, fout);
10518         }
10519
10520         if (strcmp(typalign, "c") == 0)
10521                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10522         else if (strcmp(typalign, "s") == 0)
10523                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10524         else if (strcmp(typalign, "i") == 0)
10525                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10526         else if (strcmp(typalign, "d") == 0)
10527                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10528
10529         if (strcmp(typstorage, "p") == 0)
10530                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10531         else if (strcmp(typstorage, "e") == 0)
10532                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10533         else if (strcmp(typstorage, "x") == 0)
10534                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10535         else if (strcmp(typstorage, "m") == 0)
10536                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10537
10538         if (strcmp(typbyval, "t") == 0)
10539                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10540
10541         appendPQExpBufferStr(q, "\n);\n");
10542
10543         if (dopt->binary_upgrade)
10544                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10545                                                                                 "TYPE", qtypname,
10546                                                                                 tyinfo->dobj.namespace->dobj.name);
10547
10548         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10549                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10550                                          tyinfo->dobj.name,
10551                                          tyinfo->dobj.namespace->dobj.name,
10552                                          NULL,
10553                                          tyinfo->rolname, false,
10554                                          "TYPE", SECTION_PRE_DATA,
10555                                          q->data, delq->data, NULL,
10556                                          NULL, 0,
10557                                          NULL, NULL);
10558
10559         /* Dump Type Comments and Security Labels */
10560         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10561                 dumpComment(fout, "TYPE", qtypname,
10562                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10563                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10564
10565         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10566                 dumpSecLabel(fout, "TYPE", qtypname,
10567                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10568                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10569
10570         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10571                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10572                                 qtypname, NULL,
10573                                 tyinfo->dobj.namespace->dobj.name,
10574                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10575                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10576
10577         PQclear(res);
10578         destroyPQExpBuffer(q);
10579         destroyPQExpBuffer(delq);
10580         destroyPQExpBuffer(query);
10581         free(qtypname);
10582         free(qualtypname);
10583 }
10584
10585 /*
10586  * dumpDomain
10587  *        writes out to fout the queries to recreate a user-defined domain
10588  */
10589 static void
10590 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10591 {
10592         DumpOptions *dopt = fout->dopt;
10593         PQExpBuffer q = createPQExpBuffer();
10594         PQExpBuffer delq = createPQExpBuffer();
10595         PQExpBuffer query = createPQExpBuffer();
10596         PGresult   *res;
10597         int                     i;
10598         char       *qtypname;
10599         char       *qualtypname;
10600         char       *typnotnull;
10601         char       *typdefn;
10602         char       *typdefault;
10603         Oid                     typcollation;
10604         bool            typdefault_is_literal = false;
10605
10606         /* Fetch domain specific details */
10607         if (fout->remoteVersion >= 90100)
10608         {
10609                 /* typcollation is new in 9.1 */
10610                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10611                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10612                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10613                                                   "t.typdefault, "
10614                                                   "CASE WHEN t.typcollation <> u.typcollation "
10615                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10616                                                   "FROM pg_catalog.pg_type t "
10617                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10618                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10619                                                   tyinfo->dobj.catId.oid);
10620         }
10621         else
10622         {
10623                 appendPQExpBuffer(query, "SELECT typnotnull, "
10624                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10625                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10626                                                   "typdefault, 0 AS typcollation "
10627                                                   "FROM pg_catalog.pg_type "
10628                                                   "WHERE oid = '%u'::pg_catalog.oid",
10629                                                   tyinfo->dobj.catId.oid);
10630         }
10631
10632         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10633
10634         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10635         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10636         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10637                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10638         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10639         {
10640                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10641                 typdefault_is_literal = true;   /* it needs quotes */
10642         }
10643         else
10644                 typdefault = NULL;
10645         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10646
10647         if (dopt->binary_upgrade)
10648                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10649                                                                                                  tyinfo->dobj.catId.oid,
10650                                                                                                  true); /* force array type */
10651
10652         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10653         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10654
10655         appendPQExpBuffer(q,
10656                                           "CREATE DOMAIN %s AS %s",
10657                                           qualtypname,
10658                                           typdefn);
10659
10660         /* Print collation only if different from base type's collation */
10661         if (OidIsValid(typcollation))
10662         {
10663                 CollInfo   *coll;
10664
10665                 coll = findCollationByOid(typcollation);
10666                 if (coll)
10667                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10668         }
10669
10670         if (typnotnull[0] == 't')
10671                 appendPQExpBufferStr(q, " NOT NULL");
10672
10673         if (typdefault != NULL)
10674         {
10675                 appendPQExpBufferStr(q, " DEFAULT ");
10676                 if (typdefault_is_literal)
10677                         appendStringLiteralAH(q, typdefault, fout);
10678                 else
10679                         appendPQExpBufferStr(q, typdefault);
10680         }
10681
10682         PQclear(res);
10683
10684         /*
10685          * Add any CHECK constraints for the domain
10686          */
10687         for (i = 0; i < tyinfo->nDomChecks; i++)
10688         {
10689                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10690
10691                 if (!domcheck->separate)
10692                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10693                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10694         }
10695
10696         appendPQExpBufferStr(q, ";\n");
10697
10698         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10699
10700         if (dopt->binary_upgrade)
10701                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10702                                                                                 "DOMAIN", qtypname,
10703                                                                                 tyinfo->dobj.namespace->dobj.name);
10704
10705         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10706                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10707                                          tyinfo->dobj.name,
10708                                          tyinfo->dobj.namespace->dobj.name,
10709                                          NULL,
10710                                          tyinfo->rolname, false,
10711                                          "DOMAIN", SECTION_PRE_DATA,
10712                                          q->data, delq->data, NULL,
10713                                          NULL, 0,
10714                                          NULL, NULL);
10715
10716         /* Dump Domain Comments and Security Labels */
10717         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10718                 dumpComment(fout, "DOMAIN", qtypname,
10719                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10720                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10721
10722         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10723                 dumpSecLabel(fout, "DOMAIN", qtypname,
10724                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10725                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10726
10727         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10728                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10729                                 qtypname, NULL,
10730                                 tyinfo->dobj.namespace->dobj.name,
10731                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10732                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10733
10734         /* Dump any per-constraint comments */
10735         for (i = 0; i < tyinfo->nDomChecks; i++)
10736         {
10737                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10738                 PQExpBuffer conprefix = createPQExpBuffer();
10739
10740                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10741                                                   fmtId(domcheck->dobj.name));
10742
10743                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10744                         dumpComment(fout, conprefix->data, qtypname,
10745                                                 tyinfo->dobj.namespace->dobj.name,
10746                                                 tyinfo->rolname,
10747                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10748
10749                 destroyPQExpBuffer(conprefix);
10750         }
10751
10752         destroyPQExpBuffer(q);
10753         destroyPQExpBuffer(delq);
10754         destroyPQExpBuffer(query);
10755         free(qtypname);
10756         free(qualtypname);
10757 }
10758
10759 /*
10760  * dumpCompositeType
10761  *        writes out to fout the queries to recreate a user-defined stand-alone
10762  *        composite type
10763  */
10764 static void
10765 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10766 {
10767         DumpOptions *dopt = fout->dopt;
10768         PQExpBuffer q = createPQExpBuffer();
10769         PQExpBuffer dropped = createPQExpBuffer();
10770         PQExpBuffer delq = createPQExpBuffer();
10771         PQExpBuffer query = createPQExpBuffer();
10772         PGresult   *res;
10773         char       *qtypname;
10774         char       *qualtypname;
10775         int                     ntups;
10776         int                     i_attname;
10777         int                     i_atttypdefn;
10778         int                     i_attlen;
10779         int                     i_attalign;
10780         int                     i_attisdropped;
10781         int                     i_attcollation;
10782         int                     i;
10783         int                     actual_atts;
10784
10785         /* Fetch type specific details */
10786         if (fout->remoteVersion >= 90100)
10787         {
10788                 /*
10789                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10790                  * clauses for attributes whose collation is different from their
10791                  * type's default, we use a CASE here to suppress uninteresting
10792                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10793                  * collation does not matter for those.
10794                  */
10795                 appendPQExpBuffer(query, "SELECT a.attname, "
10796                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10797                                                   "a.attlen, a.attalign, a.attisdropped, "
10798                                                   "CASE WHEN a.attcollation <> at.typcollation "
10799                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10800                                                   "FROM pg_catalog.pg_type ct "
10801                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10802                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10803                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10804                                                   "ORDER BY a.attnum ",
10805                                                   tyinfo->dobj.catId.oid);
10806         }
10807         else
10808         {
10809                 /*
10810                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10811                  * should always be false.
10812                  */
10813                 appendPQExpBuffer(query, "SELECT a.attname, "
10814                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10815                                                   "a.attlen, a.attalign, a.attisdropped, "
10816                                                   "0 AS attcollation "
10817                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10818                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10819                                                   "AND a.attrelid = ct.typrelid "
10820                                                   "ORDER BY a.attnum ",
10821                                                   tyinfo->dobj.catId.oid);
10822         }
10823
10824         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10825
10826         ntups = PQntuples(res);
10827
10828         i_attname = PQfnumber(res, "attname");
10829         i_atttypdefn = PQfnumber(res, "atttypdefn");
10830         i_attlen = PQfnumber(res, "attlen");
10831         i_attalign = PQfnumber(res, "attalign");
10832         i_attisdropped = PQfnumber(res, "attisdropped");
10833         i_attcollation = PQfnumber(res, "attcollation");
10834
10835         if (dopt->binary_upgrade)
10836         {
10837                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10838                                                                                                  tyinfo->dobj.catId.oid,
10839                                                                                                  false);
10840                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10841         }
10842
10843         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10844         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10845
10846         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10847                                           qualtypname);
10848
10849         actual_atts = 0;
10850         for (i = 0; i < ntups; i++)
10851         {
10852                 char       *attname;
10853                 char       *atttypdefn;
10854                 char       *attlen;
10855                 char       *attalign;
10856                 bool            attisdropped;
10857                 Oid                     attcollation;
10858
10859                 attname = PQgetvalue(res, i, i_attname);
10860                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10861                 attlen = PQgetvalue(res, i, i_attlen);
10862                 attalign = PQgetvalue(res, i, i_attalign);
10863                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10864                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10865
10866                 if (attisdropped && !dopt->binary_upgrade)
10867                         continue;
10868
10869                 /* Format properly if not first attr */
10870                 if (actual_atts++ > 0)
10871                         appendPQExpBufferChar(q, ',');
10872                 appendPQExpBufferStr(q, "\n\t");
10873
10874                 if (!attisdropped)
10875                 {
10876                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10877
10878                         /* Add collation if not default for the column type */
10879                         if (OidIsValid(attcollation))
10880                         {
10881                                 CollInfo   *coll;
10882
10883                                 coll = findCollationByOid(attcollation);
10884                                 if (coll)
10885                                         appendPQExpBuffer(q, " COLLATE %s",
10886                                                                           fmtQualifiedDumpable(coll));
10887                         }
10888                 }
10889                 else
10890                 {
10891                         /*
10892                          * This is a dropped attribute and we're in binary_upgrade mode.
10893                          * Insert a placeholder for it in the CREATE TYPE command, and set
10894                          * length and alignment with direct UPDATE to the catalogs
10895                          * afterwards. See similar code in dumpTableSchema().
10896                          */
10897                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10898
10899                         /* stash separately for insertion after the CREATE TYPE */
10900                         appendPQExpBufferStr(dropped,
10901                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
10902                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10903                                                           "SET attlen = %s, "
10904                                                           "attalign = '%s', attbyval = false\n"
10905                                                           "WHERE attname = ", attlen, attalign);
10906                         appendStringLiteralAH(dropped, attname, fout);
10907                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
10908                         appendStringLiteralAH(dropped, qualtypname, fout);
10909                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10910
10911                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10912                                                           qualtypname);
10913                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10914                                                           fmtId(attname));
10915                 }
10916         }
10917         appendPQExpBufferStr(q, "\n);\n");
10918         appendPQExpBufferStr(q, dropped->data);
10919
10920         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10921
10922         if (dopt->binary_upgrade)
10923                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10924                                                                                 "TYPE", qtypname,
10925                                                                                 tyinfo->dobj.namespace->dobj.name);
10926
10927         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10928                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10929                                          tyinfo->dobj.name,
10930                                          tyinfo->dobj.namespace->dobj.name,
10931                                          NULL,
10932                                          tyinfo->rolname, false,
10933                                          "TYPE", SECTION_PRE_DATA,
10934                                          q->data, delq->data, NULL,
10935                                          NULL, 0,
10936                                          NULL, NULL);
10937
10938
10939         /* Dump Type Comments and Security Labels */
10940         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10941                 dumpComment(fout, "TYPE", qtypname,
10942                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10943                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10944
10945         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10946                 dumpSecLabel(fout, "TYPE", qtypname,
10947                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10948                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10949
10950         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10951                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10952                                 qtypname, NULL,
10953                                 tyinfo->dobj.namespace->dobj.name,
10954                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10955                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10956
10957         PQclear(res);
10958         destroyPQExpBuffer(q);
10959         destroyPQExpBuffer(dropped);
10960         destroyPQExpBuffer(delq);
10961         destroyPQExpBuffer(query);
10962         free(qtypname);
10963         free(qualtypname);
10964
10965         /* Dump any per-column comments */
10966         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10967                 dumpCompositeTypeColComments(fout, tyinfo);
10968 }
10969
10970 /*
10971  * dumpCompositeTypeColComments
10972  *        writes out to fout the queries to recreate comments on the columns of
10973  *        a user-defined stand-alone composite type
10974  */
10975 static void
10976 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
10977 {
10978         CommentItem *comments;
10979         int                     ncomments;
10980         PGresult   *res;
10981         PQExpBuffer query;
10982         PQExpBuffer target;
10983         Oid                     pgClassOid;
10984         int                     i;
10985         int                     ntups;
10986         int                     i_attname;
10987         int                     i_attnum;
10988
10989         /* do nothing, if --no-comments is supplied */
10990         if (fout->dopt->no_comments)
10991                 return;
10992
10993         query = createPQExpBuffer();
10994
10995         appendPQExpBuffer(query,
10996                                           "SELECT c.tableoid, a.attname, a.attnum "
10997                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
10998                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
10999                                           "  AND NOT a.attisdropped "
11000                                           "ORDER BY a.attnum ",
11001                                           tyinfo->typrelid);
11002
11003         /* Fetch column attnames */
11004         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11005
11006         ntups = PQntuples(res);
11007         if (ntups < 1)
11008         {
11009                 PQclear(res);
11010                 destroyPQExpBuffer(query);
11011                 return;
11012         }
11013
11014         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11015
11016         /* Search for comments associated with type's pg_class OID */
11017         ncomments = findComments(fout,
11018                                                          pgClassOid,
11019                                                          tyinfo->typrelid,
11020                                                          &comments);
11021
11022         /* If no comments exist, we're done */
11023         if (ncomments <= 0)
11024         {
11025                 PQclear(res);
11026                 destroyPQExpBuffer(query);
11027                 return;
11028         }
11029
11030         /* Build COMMENT ON statements */
11031         target = createPQExpBuffer();
11032
11033         i_attnum = PQfnumber(res, "attnum");
11034         i_attname = PQfnumber(res, "attname");
11035         while (ncomments > 0)
11036         {
11037                 const char *attname;
11038
11039                 attname = NULL;
11040                 for (i = 0; i < ntups; i++)
11041                 {
11042                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11043                         {
11044                                 attname = PQgetvalue(res, i, i_attname);
11045                                 break;
11046                         }
11047                 }
11048                 if (attname)                    /* just in case we don't find it */
11049                 {
11050                         const char *descr = comments->descr;
11051
11052                         resetPQExpBuffer(target);
11053                         appendPQExpBuffer(target, "COLUMN %s.",
11054                                                           fmtId(tyinfo->dobj.name));
11055                         appendPQExpBufferStr(target, fmtId(attname));
11056
11057                         resetPQExpBuffer(query);
11058                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11059                                                           fmtQualifiedDumpable(tyinfo));
11060                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11061                         appendStringLiteralAH(query, descr, fout);
11062                         appendPQExpBufferStr(query, ";\n");
11063
11064                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11065                                                  target->data,
11066                                                  tyinfo->dobj.namespace->dobj.name,
11067                                                  NULL, tyinfo->rolname,
11068                                                  false, "COMMENT", SECTION_NONE,
11069                                                  query->data, "", NULL,
11070                                                  &(tyinfo->dobj.dumpId), 1,
11071                                                  NULL, NULL);
11072                 }
11073
11074                 comments++;
11075                 ncomments--;
11076         }
11077
11078         PQclear(res);
11079         destroyPQExpBuffer(query);
11080         destroyPQExpBuffer(target);
11081 }
11082
11083 /*
11084  * dumpShellType
11085  *        writes out to fout the queries to create a shell type
11086  *
11087  * We dump a shell definition in advance of the I/O functions for the type.
11088  */
11089 static void
11090 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11091 {
11092         DumpOptions *dopt = fout->dopt;
11093         PQExpBuffer q;
11094
11095         /* Skip if not to be dumped */
11096         if (!stinfo->dobj.dump || dopt->dataOnly)
11097                 return;
11098
11099         q = createPQExpBuffer();
11100
11101         /*
11102          * Note the lack of a DROP command for the shell type; any required DROP
11103          * is driven off the base type entry, instead.  This interacts with
11104          * _printTocEntry()'s use of the presence of a DROP command to decide
11105          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11106          * the shell type's owner immediately on creation; that should happen only
11107          * after it's filled in, otherwise the backend complains.
11108          */
11109
11110         if (dopt->binary_upgrade)
11111                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11112                                                                                                  stinfo->baseType->dobj.catId.oid,
11113                                                                                                  false);
11114
11115         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11116                                           fmtQualifiedDumpable(stinfo));
11117
11118         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11119                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11120                                          stinfo->dobj.name,
11121                                          stinfo->dobj.namespace->dobj.name,
11122                                          NULL,
11123                                          stinfo->baseType->rolname, false,
11124                                          "SHELL TYPE", SECTION_PRE_DATA,
11125                                          q->data, "", NULL,
11126                                          NULL, 0,
11127                                          NULL, NULL);
11128
11129         destroyPQExpBuffer(q);
11130 }
11131
11132 /*
11133  * dumpProcLang
11134  *                writes out to fout the queries to recreate a user-defined
11135  *                procedural language
11136  */
11137 static void
11138 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11139 {
11140         DumpOptions *dopt = fout->dopt;
11141         PQExpBuffer defqry;
11142         PQExpBuffer delqry;
11143         bool            useParams;
11144         char       *qlanname;
11145         FuncInfo   *funcInfo;
11146         FuncInfo   *inlineInfo = NULL;
11147         FuncInfo   *validatorInfo = NULL;
11148
11149         /* Skip if not to be dumped */
11150         if (!plang->dobj.dump || dopt->dataOnly)
11151                 return;
11152
11153         /*
11154          * Try to find the support function(s).  It is not an error if we don't
11155          * find them --- if the functions are in the pg_catalog schema, as is
11156          * standard in 8.1 and up, then we won't have loaded them. (In this case
11157          * we will emit a parameterless CREATE LANGUAGE command, which will
11158          * require PL template knowledge in the backend to reload.)
11159          */
11160
11161         funcInfo = findFuncByOid(plang->lanplcallfoid);
11162         if (funcInfo != NULL && !funcInfo->dobj.dump)
11163                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11164
11165         if (OidIsValid(plang->laninline))
11166         {
11167                 inlineInfo = findFuncByOid(plang->laninline);
11168                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11169                         inlineInfo = NULL;
11170         }
11171
11172         if (OidIsValid(plang->lanvalidator))
11173         {
11174                 validatorInfo = findFuncByOid(plang->lanvalidator);
11175                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11176                         validatorInfo = NULL;
11177         }
11178
11179         /*
11180          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11181          * with parameters.  Otherwise, we'll write a parameterless command, which
11182          * will rely on data from pg_pltemplate.
11183          */
11184         useParams = (funcInfo != NULL &&
11185                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11186                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11187
11188         defqry = createPQExpBuffer();
11189         delqry = createPQExpBuffer();
11190
11191         qlanname = pg_strdup(fmtId(plang->dobj.name));
11192
11193         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11194                                           qlanname);
11195
11196         if (useParams)
11197         {
11198                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11199                                                   plang->lanpltrusted ? "TRUSTED " : "",
11200                                                   qlanname);
11201                 appendPQExpBuffer(defqry, " HANDLER %s",
11202                                                   fmtQualifiedDumpable(funcInfo));
11203                 if (OidIsValid(plang->laninline))
11204                         appendPQExpBuffer(defqry, " INLINE %s",
11205                                                           fmtQualifiedDumpable(inlineInfo));
11206                 if (OidIsValid(plang->lanvalidator))
11207                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11208                                                           fmtQualifiedDumpable(validatorInfo));
11209         }
11210         else
11211         {
11212                 /*
11213                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11214                  * command will not fail if the language is preinstalled in the target
11215                  * database.  We restrict the use of REPLACE to this case so as to
11216                  * eliminate the risk of replacing a language with incompatible
11217                  * parameter settings: this command will only succeed at all if there
11218                  * is a pg_pltemplate entry, and if there is one, the existing entry
11219                  * must match it too.
11220                  */
11221                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11222                                                   qlanname);
11223         }
11224         appendPQExpBufferStr(defqry, ";\n");
11225
11226         if (dopt->binary_upgrade)
11227                 binary_upgrade_extension_member(defqry, &plang->dobj,
11228                                                                                 "LANGUAGE", qlanname, NULL);
11229
11230         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11231                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11232                                          plang->dobj.name,
11233                                          NULL, NULL, plang->lanowner,
11234                                          false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11235                                          defqry->data, delqry->data, NULL,
11236                                          NULL, 0,
11237                                          NULL, NULL);
11238
11239         /* Dump Proc Lang Comments and Security Labels */
11240         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11241                 dumpComment(fout, "LANGUAGE", qlanname,
11242                                         NULL, plang->lanowner,
11243                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11244
11245         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11246                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11247                                          NULL, plang->lanowner,
11248                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11249
11250         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11251                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11252                                 qlanname, NULL, NULL,
11253                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11254                                 plang->initlanacl, plang->initrlanacl);
11255
11256         free(qlanname);
11257
11258         destroyPQExpBuffer(defqry);
11259         destroyPQExpBuffer(delqry);
11260 }
11261
11262 /*
11263  * format_function_arguments: generate function name and argument list
11264  *
11265  * This is used when we can rely on pg_get_function_arguments to format
11266  * the argument list.  Note, however, that pg_get_function_arguments
11267  * does not special-case zero-argument aggregates.
11268  */
11269 static char *
11270 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11271 {
11272         PQExpBufferData fn;
11273
11274         initPQExpBuffer(&fn);
11275         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11276         if (is_agg && finfo->nargs == 0)
11277                 appendPQExpBufferStr(&fn, "(*)");
11278         else
11279                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11280         return fn.data;
11281 }
11282
11283 /*
11284  * format_function_arguments_old: generate function name and argument list
11285  *
11286  * The argument type names are qualified if needed.  The function name
11287  * is never qualified.
11288  *
11289  * This is used only with pre-8.4 servers, so we aren't expecting to see
11290  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11291  *
11292  * Any or all of allargtypes, argmodes, argnames may be NULL.
11293  */
11294 static char *
11295 format_function_arguments_old(Archive *fout,
11296                                                           FuncInfo *finfo, int nallargs,
11297                                                           char **allargtypes,
11298                                                           char **argmodes,
11299                                                           char **argnames)
11300 {
11301         PQExpBufferData fn;
11302         int                     j;
11303
11304         initPQExpBuffer(&fn);
11305         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11306         for (j = 0; j < nallargs; j++)
11307         {
11308                 Oid                     typid;
11309                 char       *typname;
11310                 const char *argmode;
11311                 const char *argname;
11312
11313                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11314                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11315
11316                 if (argmodes)
11317                 {
11318                         switch (argmodes[j][0])
11319                         {
11320                                 case PROARGMODE_IN:
11321                                         argmode = "";
11322                                         break;
11323                                 case PROARGMODE_OUT:
11324                                         argmode = "OUT ";
11325                                         break;
11326                                 case PROARGMODE_INOUT:
11327                                         argmode = "INOUT ";
11328                                         break;
11329                                 default:
11330                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11331                                         argmode = "";
11332                                         break;
11333                         }
11334                 }
11335                 else
11336                         argmode = "";
11337
11338                 argname = argnames ? argnames[j] : (char *) NULL;
11339                 if (argname && argname[0] == '\0')
11340                         argname = NULL;
11341
11342                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11343                                                   (j > 0) ? ", " : "",
11344                                                   argmode,
11345                                                   argname ? fmtId(argname) : "",
11346                                                   argname ? " " : "",
11347                                                   typname);
11348                 free(typname);
11349         }
11350         appendPQExpBufferChar(&fn, ')');
11351         return fn.data;
11352 }
11353
11354 /*
11355  * format_function_signature: generate function name and argument list
11356  *
11357  * This is like format_function_arguments_old except that only a minimal
11358  * list of input argument types is generated; this is sufficient to
11359  * reference the function, but not to define it.
11360  *
11361  * If honor_quotes is false then the function name is never quoted.
11362  * This is appropriate for use in TOC tags, but not in SQL commands.
11363  */
11364 static char *
11365 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11366 {
11367         PQExpBufferData fn;
11368         int                     j;
11369
11370         initPQExpBuffer(&fn);
11371         if (honor_quotes)
11372                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11373         else
11374                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11375         for (j = 0; j < finfo->nargs; j++)
11376         {
11377                 char       *typname;
11378
11379                 if (j > 0)
11380                         appendPQExpBufferStr(&fn, ", ");
11381
11382                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11383                                                                            zeroAsOpaque);
11384                 appendPQExpBufferStr(&fn, typname);
11385                 free(typname);
11386         }
11387         appendPQExpBufferChar(&fn, ')');
11388         return fn.data;
11389 }
11390
11391
11392 /*
11393  * dumpFunc:
11394  *        dump out one function
11395  */
11396 static void
11397 dumpFunc(Archive *fout, FuncInfo *finfo)
11398 {
11399         DumpOptions *dopt = fout->dopt;
11400         PQExpBuffer query;
11401         PQExpBuffer q;
11402         PQExpBuffer delqry;
11403         PQExpBuffer asPart;
11404         PGresult   *res;
11405         char       *funcsig;            /* identity signature */
11406         char       *funcfullsig = NULL; /* full signature */
11407         char       *funcsig_tag;
11408         char       *proretset;
11409         char       *prosrc;
11410         char       *probin;
11411         char       *funcargs;
11412         char       *funciargs;
11413         char       *funcresult;
11414         bool            is_procedure;
11415         char       *proallargtypes;
11416         char       *proargmodes;
11417         char       *proargnames;
11418         char       *protrftypes;
11419         char       *proiswindow;
11420         char       *provolatile;
11421         char       *proisstrict;
11422         char       *prosecdef;
11423         char       *proleakproof;
11424         char       *proconfig;
11425         char       *procost;
11426         char       *prorows;
11427         char       *proparallel;
11428         char       *lanname;
11429         char       *rettypename;
11430         int                     nallargs;
11431         char      **allargtypes = NULL;
11432         char      **argmodes = NULL;
11433         char      **argnames = NULL;
11434         char      **configitems = NULL;
11435         int                     nconfigitems = 0;
11436         const char *keyword;
11437         int                     i;
11438
11439         /* Skip if not to be dumped */
11440         if (!finfo->dobj.dump || dopt->dataOnly)
11441                 return;
11442
11443         query = createPQExpBuffer();
11444         q = createPQExpBuffer();
11445         delqry = createPQExpBuffer();
11446         asPart = createPQExpBuffer();
11447
11448         /* Fetch function-specific details */
11449         if (fout->remoteVersion >= 90600)
11450         {
11451                 /*
11452                  * proparallel was added in 9.6
11453                  */
11454                 appendPQExpBuffer(query,
11455                                                   "SELECT proretset, prosrc, probin, "
11456                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11457                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11458                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11459                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11460                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
11461                                                   "proleakproof, proconfig, procost, prorows, "
11462                                                   "proparallel, "
11463                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11464                                                   "FROM pg_catalog.pg_proc "
11465                                                   "WHERE oid = '%u'::pg_catalog.oid",
11466                                                   finfo->dobj.catId.oid);
11467         }
11468         else if (fout->remoteVersion >= 90500)
11469         {
11470                 /*
11471                  * protrftypes was added in 9.5
11472                  */
11473                 appendPQExpBuffer(query,
11474                                                   "SELECT proretset, prosrc, probin, "
11475                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11476                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11477                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11478                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11479                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
11480                                                   "proleakproof, proconfig, procost, prorows, "
11481                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11482                                                   "FROM pg_catalog.pg_proc "
11483                                                   "WHERE oid = '%u'::pg_catalog.oid",
11484                                                   finfo->dobj.catId.oid);
11485         }
11486         else if (fout->remoteVersion >= 90200)
11487         {
11488                 /*
11489                  * proleakproof was added in 9.2
11490                  */
11491                 appendPQExpBuffer(query,
11492                                                   "SELECT proretset, prosrc, probin, "
11493                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11494                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11495                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11496                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
11497                                                   "proleakproof, proconfig, procost, prorows, "
11498                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11499                                                   "FROM pg_catalog.pg_proc "
11500                                                   "WHERE oid = '%u'::pg_catalog.oid",
11501                                                   finfo->dobj.catId.oid);
11502         }
11503         else if (fout->remoteVersion >= 80400)
11504         {
11505                 /*
11506                  * In 8.4 and up we rely on pg_get_function_arguments and
11507                  * pg_get_function_result instead of examining proallargtypes etc.
11508                  */
11509                 appendPQExpBuffer(query,
11510                                                   "SELECT proretset, prosrc, probin, "
11511                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11512                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11513                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11514                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
11515                                                   "false AS proleakproof, "
11516                                                   " proconfig, procost, prorows, "
11517                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11518                                                   "FROM pg_catalog.pg_proc "
11519                                                   "WHERE oid = '%u'::pg_catalog.oid",
11520                                                   finfo->dobj.catId.oid);
11521         }
11522         else if (fout->remoteVersion >= 80300)
11523         {
11524                 appendPQExpBuffer(query,
11525                                                   "SELECT proretset, prosrc, probin, "
11526                                                   "proallargtypes, proargmodes, proargnames, "
11527                                                   "false AS proiswindow, "
11528                                                   "provolatile, proisstrict, prosecdef, "
11529                                                   "false AS proleakproof, "
11530                                                   "proconfig, procost, prorows, "
11531                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11532                                                   "FROM pg_catalog.pg_proc "
11533                                                   "WHERE oid = '%u'::pg_catalog.oid",
11534                                                   finfo->dobj.catId.oid);
11535         }
11536         else if (fout->remoteVersion >= 80100)
11537         {
11538                 appendPQExpBuffer(query,
11539                                                   "SELECT proretset, prosrc, probin, "
11540                                                   "proallargtypes, proargmodes, proargnames, "
11541                                                   "false AS proiswindow, "
11542                                                   "provolatile, proisstrict, prosecdef, "
11543                                                   "false AS proleakproof, "
11544                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11545                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11546                                                   "FROM pg_catalog.pg_proc "
11547                                                   "WHERE oid = '%u'::pg_catalog.oid",
11548                                                   finfo->dobj.catId.oid);
11549         }
11550         else
11551         {
11552                 appendPQExpBuffer(query,
11553                                                   "SELECT proretset, prosrc, probin, "
11554                                                   "null AS proallargtypes, "
11555                                                   "null AS proargmodes, "
11556                                                   "proargnames, "
11557                                                   "false AS proiswindow, "
11558                                                   "provolatile, proisstrict, prosecdef, "
11559                                                   "false AS proleakproof, "
11560                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11561                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11562                                                   "FROM pg_catalog.pg_proc "
11563                                                   "WHERE oid = '%u'::pg_catalog.oid",
11564                                                   finfo->dobj.catId.oid);
11565         }
11566
11567         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11568
11569         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11570         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11571         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11572         if (fout->remoteVersion >= 80400)
11573         {
11574                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11575                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11576                 is_procedure = PQgetisnull(res, 0, PQfnumber(res, "funcresult"));
11577                 if (is_procedure)
11578                         funcresult = NULL;
11579                 else
11580                         funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11581                 proallargtypes = proargmodes = proargnames = NULL;
11582         }
11583         else
11584         {
11585                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11586                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11587                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11588                 funcargs = funciargs = funcresult = NULL;
11589                 is_procedure = false;
11590         }
11591         if (PQfnumber(res, "protrftypes") != -1)
11592                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11593         else
11594                 protrftypes = NULL;
11595         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
11596         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11597         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11598         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11599         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11600         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11601         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11602         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11603
11604         if (PQfnumber(res, "proparallel") != -1)
11605                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11606         else
11607                 proparallel = NULL;
11608
11609         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11610
11611         /*
11612          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11613          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11614          * versions would set it to "-".  There are no known cases in which prosrc
11615          * is unused, so the tests below for "-" are probably useless.
11616          */
11617         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11618         {
11619                 appendPQExpBufferStr(asPart, "AS ");
11620                 appendStringLiteralAH(asPart, probin, fout);
11621                 if (strcmp(prosrc, "-") != 0)
11622                 {
11623                         appendPQExpBufferStr(asPart, ", ");
11624
11625                         /*
11626                          * where we have bin, use dollar quoting if allowed and src
11627                          * contains quote or backslash; else use regular quoting.
11628                          */
11629                         if (dopt->disable_dollar_quoting ||
11630                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11631                                 appendStringLiteralAH(asPart, prosrc, fout);
11632                         else
11633                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11634                 }
11635         }
11636         else
11637         {
11638                 if (strcmp(prosrc, "-") != 0)
11639                 {
11640                         appendPQExpBufferStr(asPart, "AS ");
11641                         /* with no bin, dollar quote src unconditionally if allowed */
11642                         if (dopt->disable_dollar_quoting)
11643                                 appendStringLiteralAH(asPart, prosrc, fout);
11644                         else
11645                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11646                 }
11647         }
11648
11649         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11650
11651         if (proallargtypes && *proallargtypes)
11652         {
11653                 int                     nitems = 0;
11654
11655                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11656                         nitems < finfo->nargs)
11657                 {
11658                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11659                         if (allargtypes)
11660                                 free(allargtypes);
11661                         allargtypes = NULL;
11662                 }
11663                 else
11664                         nallargs = nitems;
11665         }
11666
11667         if (proargmodes && *proargmodes)
11668         {
11669                 int                     nitems = 0;
11670
11671                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11672                         nitems != nallargs)
11673                 {
11674                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11675                         if (argmodes)
11676                                 free(argmodes);
11677                         argmodes = NULL;
11678                 }
11679         }
11680
11681         if (proargnames && *proargnames)
11682         {
11683                 int                     nitems = 0;
11684
11685                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11686                         nitems != nallargs)
11687                 {
11688                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11689                         if (argnames)
11690                                 free(argnames);
11691                         argnames = NULL;
11692                 }
11693         }
11694
11695         if (proconfig && *proconfig)
11696         {
11697                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11698                 {
11699                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11700                         if (configitems)
11701                                 free(configitems);
11702                         configitems = NULL;
11703                         nconfigitems = 0;
11704                 }
11705         }
11706
11707         if (funcargs)
11708         {
11709                 /* 8.4 or later; we rely on server-side code for most of the work */
11710                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11711                 funcsig = format_function_arguments(finfo, funciargs, false);
11712         }
11713         else
11714                 /* pre-8.4, do it ourselves */
11715                 funcsig = format_function_arguments_old(fout,
11716                                                                                                 finfo, nallargs, allargtypes,
11717                                                                                                 argmodes, argnames);
11718
11719         funcsig_tag = format_function_signature(fout, finfo, false);
11720
11721         keyword = is_procedure ? "PROCEDURE" : "FUNCTION";
11722
11723         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11724                                           keyword,
11725                                           fmtId(finfo->dobj.namespace->dobj.name),
11726                                           funcsig);
11727
11728         appendPQExpBuffer(q, "CREATE %s %s.%s",
11729                                           keyword,
11730                                           fmtId(finfo->dobj.namespace->dobj.name),
11731                                           funcfullsig ? funcfullsig :
11732                                           funcsig);
11733
11734         if (is_procedure)
11735                 ;
11736         else if (funcresult)
11737                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11738         else
11739         {
11740                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11741                                                                                    zeroAsOpaque);
11742                 appendPQExpBuffer(q, " RETURNS %s%s",
11743                                                   (proretset[0] == 't') ? "SETOF " : "",
11744                                                   rettypename);
11745                 free(rettypename);
11746         }
11747
11748         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11749
11750         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11751         {
11752                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11753                 int                     i;
11754
11755                 appendPQExpBufferStr(q, " TRANSFORM ");
11756                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11757                 for (i = 0; typeids[i]; i++)
11758                 {
11759                         if (i != 0)
11760                                 appendPQExpBufferStr(q, ", ");
11761                         appendPQExpBuffer(q, "FOR TYPE %s",
11762                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11763                 }
11764         }
11765
11766         if (proiswindow[0] == 't')
11767                 appendPQExpBufferStr(q, " WINDOW");
11768
11769         if (provolatile[0] != PROVOLATILE_VOLATILE)
11770         {
11771                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11772                         appendPQExpBufferStr(q, " IMMUTABLE");
11773                 else if (provolatile[0] == PROVOLATILE_STABLE)
11774                         appendPQExpBufferStr(q, " STABLE");
11775                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11776                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11777                                                   finfo->dobj.name);
11778         }
11779
11780         if (proisstrict[0] == 't')
11781                 appendPQExpBufferStr(q, " STRICT");
11782
11783         if (prosecdef[0] == 't')
11784                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11785
11786         if (proleakproof[0] == 't')
11787                 appendPQExpBufferStr(q, " LEAKPROOF");
11788
11789         /*
11790          * COST and ROWS are emitted only if present and not default, so as not to
11791          * break backwards-compatibility of the dump without need.  Keep this code
11792          * in sync with the defaults in functioncmds.c.
11793          */
11794         if (strcmp(procost, "0") != 0)
11795         {
11796                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11797                 {
11798                         /* default cost is 1 */
11799                         if (strcmp(procost, "1") != 0)
11800                                 appendPQExpBuffer(q, " COST %s", procost);
11801                 }
11802                 else
11803                 {
11804                         /* default cost is 100 */
11805                         if (strcmp(procost, "100") != 0)
11806                                 appendPQExpBuffer(q, " COST %s", procost);
11807                 }
11808         }
11809         if (proretset[0] == 't' &&
11810                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11811                 appendPQExpBuffer(q, " ROWS %s", prorows);
11812
11813         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11814         {
11815                 if (proparallel[0] == PROPARALLEL_SAFE)
11816                         appendPQExpBufferStr(q, " PARALLEL SAFE");
11817                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11818                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11819                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
11820                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11821                                                   finfo->dobj.name);
11822         }
11823
11824         for (i = 0; i < nconfigitems; i++)
11825         {
11826                 /* we feel free to scribble on configitems[] here */
11827                 char       *configitem = configitems[i];
11828                 char       *pos;
11829
11830                 pos = strchr(configitem, '=');
11831                 if (pos == NULL)
11832                         continue;
11833                 *pos++ = '\0';
11834                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
11835
11836                 /*
11837                  * Some GUC variable names are 'LIST' type and hence must not be
11838                  * quoted.
11839                  */
11840                 if (pg_strcasecmp(configitem, "DateStyle") == 0
11841                         || pg_strcasecmp(configitem, "search_path") == 0)
11842                         appendPQExpBufferStr(q, pos);
11843                 else
11844                         appendStringLiteralAH(q, pos, fout);
11845         }
11846
11847         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
11848
11849         if (dopt->binary_upgrade)
11850                 binary_upgrade_extension_member(q, &finfo->dobj,
11851                                                                                 keyword, funcsig,
11852                                                                                 finfo->dobj.namespace->dobj.name);
11853
11854         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11855                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11856                                          funcsig_tag,
11857                                          finfo->dobj.namespace->dobj.name,
11858                                          NULL,
11859                                          finfo->rolname, false,
11860                                          keyword, SECTION_PRE_DATA,
11861                                          q->data, delqry->data, NULL,
11862                                          NULL, 0,
11863                                          NULL, NULL);
11864
11865         /* Dump Function Comments and Security Labels */
11866         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11867                 dumpComment(fout, keyword, funcsig,
11868                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
11869                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
11870
11871         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11872                 dumpSecLabel(fout, keyword, funcsig,
11873                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
11874                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
11875
11876         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
11877                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
11878                                 funcsig, NULL,
11879                                 finfo->dobj.namespace->dobj.name,
11880                                 finfo->rolname, finfo->proacl, finfo->rproacl,
11881                                 finfo->initproacl, finfo->initrproacl);
11882
11883         PQclear(res);
11884
11885         destroyPQExpBuffer(query);
11886         destroyPQExpBuffer(q);
11887         destroyPQExpBuffer(delqry);
11888         destroyPQExpBuffer(asPart);
11889         free(funcsig);
11890         if (funcfullsig)
11891                 free(funcfullsig);
11892         free(funcsig_tag);
11893         if (allargtypes)
11894                 free(allargtypes);
11895         if (argmodes)
11896                 free(argmodes);
11897         if (argnames)
11898                 free(argnames);
11899         if (configitems)
11900                 free(configitems);
11901 }
11902
11903
11904 /*
11905  * Dump a user-defined cast
11906  */
11907 static void
11908 dumpCast(Archive *fout, CastInfo *cast)
11909 {
11910         DumpOptions *dopt = fout->dopt;
11911         PQExpBuffer defqry;
11912         PQExpBuffer delqry;
11913         PQExpBuffer labelq;
11914         PQExpBuffer castargs;
11915         FuncInfo   *funcInfo = NULL;
11916         char       *sourceType;
11917         char       *targetType;
11918
11919         /* Skip if not to be dumped */
11920         if (!cast->dobj.dump || dopt->dataOnly)
11921                 return;
11922
11923         /* Cannot dump if we don't have the cast function's info */
11924         if (OidIsValid(cast->castfunc))
11925         {
11926                 funcInfo = findFuncByOid(cast->castfunc);
11927                 if (funcInfo == NULL)
11928                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
11929                                                   cast->castfunc);
11930         }
11931
11932         defqry = createPQExpBuffer();
11933         delqry = createPQExpBuffer();
11934         labelq = createPQExpBuffer();
11935         castargs = createPQExpBuffer();
11936
11937         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
11938         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
11939         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
11940                                           sourceType, targetType);
11941
11942         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
11943                                           sourceType, targetType);
11944
11945         switch (cast->castmethod)
11946         {
11947                 case COERCION_METHOD_BINARY:
11948                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
11949                         break;
11950                 case COERCION_METHOD_INOUT:
11951                         appendPQExpBufferStr(defqry, "WITH INOUT");
11952                         break;
11953                 case COERCION_METHOD_FUNCTION:
11954                         if (funcInfo)
11955                         {
11956                                 char       *fsig = format_function_signature(fout, funcInfo, true);
11957
11958                                 /*
11959                                  * Always qualify the function name (format_function_signature
11960                                  * won't qualify it).
11961                                  */
11962                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
11963                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
11964                                 free(fsig);
11965                         }
11966                         else
11967                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
11968                         break;
11969                 default:
11970                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
11971         }
11972
11973         if (cast->castcontext == 'a')
11974                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
11975         else if (cast->castcontext == 'i')
11976                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
11977         appendPQExpBufferStr(defqry, ";\n");
11978
11979         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
11980                                           sourceType, targetType);
11981
11982         appendPQExpBuffer(castargs, "(%s AS %s)",
11983                                           sourceType, targetType);
11984
11985         if (dopt->binary_upgrade)
11986                 binary_upgrade_extension_member(defqry, &cast->dobj,
11987                                                                                 "CAST", castargs->data, NULL);
11988
11989         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
11990                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
11991                                          labelq->data,
11992                                          NULL, NULL, "",
11993                                          false, "CAST", SECTION_PRE_DATA,
11994                                          defqry->data, delqry->data, NULL,
11995                                          NULL, 0,
11996                                          NULL, NULL);
11997
11998         /* Dump Cast Comments */
11999         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12000                 dumpComment(fout, "CAST", castargs->data,
12001                                         NULL, "",
12002                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12003
12004         free(sourceType);
12005         free(targetType);
12006
12007         destroyPQExpBuffer(defqry);
12008         destroyPQExpBuffer(delqry);
12009         destroyPQExpBuffer(labelq);
12010         destroyPQExpBuffer(castargs);
12011 }
12012
12013 /*
12014  * Dump a transform
12015  */
12016 static void
12017 dumpTransform(Archive *fout, TransformInfo *transform)
12018 {
12019         DumpOptions *dopt = fout->dopt;
12020         PQExpBuffer defqry;
12021         PQExpBuffer delqry;
12022         PQExpBuffer labelq;
12023         PQExpBuffer transformargs;
12024         FuncInfo   *fromsqlFuncInfo = NULL;
12025         FuncInfo   *tosqlFuncInfo = NULL;
12026         char       *lanname;
12027         char       *transformType;
12028
12029         /* Skip if not to be dumped */
12030         if (!transform->dobj.dump || dopt->dataOnly)
12031                 return;
12032
12033         /* Cannot dump if we don't have the transform functions' info */
12034         if (OidIsValid(transform->trffromsql))
12035         {
12036                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12037                 if (fromsqlFuncInfo == NULL)
12038                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12039                                                   transform->trffromsql);
12040         }
12041         if (OidIsValid(transform->trftosql))
12042         {
12043                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12044                 if (tosqlFuncInfo == NULL)
12045                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12046                                                   transform->trftosql);
12047         }
12048
12049         defqry = createPQExpBuffer();
12050         delqry = createPQExpBuffer();
12051         labelq = createPQExpBuffer();
12052         transformargs = createPQExpBuffer();
12053
12054         lanname = get_language_name(fout, transform->trflang);
12055         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12056
12057         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12058                                           transformType, lanname);
12059
12060         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12061                                           transformType, lanname);
12062
12063         if (!transform->trffromsql && !transform->trftosql)
12064                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12065
12066         if (transform->trffromsql)
12067         {
12068                 if (fromsqlFuncInfo)
12069                 {
12070                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12071
12072                         /*
12073                          * Always qualify the function name (format_function_signature
12074                          * won't qualify it).
12075                          */
12076                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12077                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12078                         free(fsig);
12079                 }
12080                 else
12081                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12082         }
12083
12084         if (transform->trftosql)
12085         {
12086                 if (transform->trffromsql)
12087                         appendPQExpBuffer(defqry, ", ");
12088
12089                 if (tosqlFuncInfo)
12090                 {
12091                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12092
12093                         /*
12094                          * Always qualify the function name (format_function_signature
12095                          * won't qualify it).
12096                          */
12097                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12098                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12099                         free(fsig);
12100                 }
12101                 else
12102                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12103         }
12104
12105         appendPQExpBuffer(defqry, ");\n");
12106
12107         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12108                                           transformType, lanname);
12109
12110         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12111                                           transformType, lanname);
12112
12113         if (dopt->binary_upgrade)
12114                 binary_upgrade_extension_member(defqry, &transform->dobj,
12115                                                                                 "TRANSFORM", transformargs->data, NULL);
12116
12117         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12118                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12119                                          labelq->data,
12120                                          NULL, NULL, "",
12121                                          false, "TRANSFORM", SECTION_PRE_DATA,
12122                                          defqry->data, delqry->data, NULL,
12123                                          transform->dobj.dependencies, transform->dobj.nDeps,
12124                                          NULL, NULL);
12125
12126         /* Dump Transform Comments */
12127         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12128                 dumpComment(fout, "TRANSFORM", transformargs->data,
12129                                         NULL, "",
12130                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12131
12132         free(lanname);
12133         free(transformType);
12134         destroyPQExpBuffer(defqry);
12135         destroyPQExpBuffer(delqry);
12136         destroyPQExpBuffer(labelq);
12137         destroyPQExpBuffer(transformargs);
12138 }
12139
12140
12141 /*
12142  * dumpOpr
12143  *        write out a single operator definition
12144  */
12145 static void
12146 dumpOpr(Archive *fout, OprInfo *oprinfo)
12147 {
12148         DumpOptions *dopt = fout->dopt;
12149         PQExpBuffer query;
12150         PQExpBuffer q;
12151         PQExpBuffer delq;
12152         PQExpBuffer oprid;
12153         PQExpBuffer details;
12154         PGresult   *res;
12155         int                     i_oprkind;
12156         int                     i_oprcode;
12157         int                     i_oprleft;
12158         int                     i_oprright;
12159         int                     i_oprcom;
12160         int                     i_oprnegate;
12161         int                     i_oprrest;
12162         int                     i_oprjoin;
12163         int                     i_oprcanmerge;
12164         int                     i_oprcanhash;
12165         char       *oprkind;
12166         char       *oprcode;
12167         char       *oprleft;
12168         char       *oprright;
12169         char       *oprcom;
12170         char       *oprnegate;
12171         char       *oprrest;
12172         char       *oprjoin;
12173         char       *oprcanmerge;
12174         char       *oprcanhash;
12175         char       *oprregproc;
12176         char       *oprref;
12177
12178         /* Skip if not to be dumped */
12179         if (!oprinfo->dobj.dump || dopt->dataOnly)
12180                 return;
12181
12182         /*
12183          * some operators are invalid because they were the result of user
12184          * defining operators before commutators exist
12185          */
12186         if (!OidIsValid(oprinfo->oprcode))
12187                 return;
12188
12189         query = createPQExpBuffer();
12190         q = createPQExpBuffer();
12191         delq = createPQExpBuffer();
12192         oprid = createPQExpBuffer();
12193         details = createPQExpBuffer();
12194
12195         if (fout->remoteVersion >= 80300)
12196         {
12197                 appendPQExpBuffer(query, "SELECT oprkind, "
12198                                                   "oprcode::pg_catalog.regprocedure, "
12199                                                   "oprleft::pg_catalog.regtype, "
12200                                                   "oprright::pg_catalog.regtype, "
12201                                                   "oprcom, "
12202                                                   "oprnegate, "
12203                                                   "oprrest::pg_catalog.regprocedure, "
12204                                                   "oprjoin::pg_catalog.regprocedure, "
12205                                                   "oprcanmerge, oprcanhash "
12206                                                   "FROM pg_catalog.pg_operator "
12207                                                   "WHERE oid = '%u'::pg_catalog.oid",
12208                                                   oprinfo->dobj.catId.oid);
12209         }
12210         else
12211         {
12212                 appendPQExpBuffer(query, "SELECT oprkind, "
12213                                                   "oprcode::pg_catalog.regprocedure, "
12214                                                   "oprleft::pg_catalog.regtype, "
12215                                                   "oprright::pg_catalog.regtype, "
12216                                                   "oprcom, "
12217                                                   "oprnegate, "
12218                                                   "oprrest::pg_catalog.regprocedure, "
12219                                                   "oprjoin::pg_catalog.regprocedure, "
12220                                                   "(oprlsortop != 0) AS oprcanmerge, "
12221                                                   "oprcanhash "
12222                                                   "FROM pg_catalog.pg_operator "
12223                                                   "WHERE oid = '%u'::pg_catalog.oid",
12224                                                   oprinfo->dobj.catId.oid);
12225         }
12226
12227         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12228
12229         i_oprkind = PQfnumber(res, "oprkind");
12230         i_oprcode = PQfnumber(res, "oprcode");
12231         i_oprleft = PQfnumber(res, "oprleft");
12232         i_oprright = PQfnumber(res, "oprright");
12233         i_oprcom = PQfnumber(res, "oprcom");
12234         i_oprnegate = PQfnumber(res, "oprnegate");
12235         i_oprrest = PQfnumber(res, "oprrest");
12236         i_oprjoin = PQfnumber(res, "oprjoin");
12237         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12238         i_oprcanhash = PQfnumber(res, "oprcanhash");
12239
12240         oprkind = PQgetvalue(res, 0, i_oprkind);
12241         oprcode = PQgetvalue(res, 0, i_oprcode);
12242         oprleft = PQgetvalue(res, 0, i_oprleft);
12243         oprright = PQgetvalue(res, 0, i_oprright);
12244         oprcom = PQgetvalue(res, 0, i_oprcom);
12245         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12246         oprrest = PQgetvalue(res, 0, i_oprrest);
12247         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12248         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12249         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12250
12251         oprregproc = convertRegProcReference(fout, oprcode);
12252         if (oprregproc)
12253         {
12254                 appendPQExpBuffer(details, "    PROCEDURE = %s", oprregproc);
12255                 free(oprregproc);
12256         }
12257
12258         appendPQExpBuffer(oprid, "%s (",
12259                                           oprinfo->dobj.name);
12260
12261         /*
12262          * right unary means there's a left arg and left unary means there's a
12263          * right arg
12264          */
12265         if (strcmp(oprkind, "r") == 0 ||
12266                 strcmp(oprkind, "b") == 0)
12267         {
12268                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12269                 appendPQExpBufferStr(oprid, oprleft);
12270         }
12271         else
12272                 appendPQExpBufferStr(oprid, "NONE");
12273
12274         if (strcmp(oprkind, "l") == 0 ||
12275                 strcmp(oprkind, "b") == 0)
12276         {
12277                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12278                 appendPQExpBuffer(oprid, ", %s)", oprright);
12279         }
12280         else
12281                 appendPQExpBufferStr(oprid, ", NONE)");
12282
12283         oprref = getFormattedOperatorName(fout, oprcom);
12284         if (oprref)
12285         {
12286                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12287                 free(oprref);
12288         }
12289
12290         oprref = getFormattedOperatorName(fout, oprnegate);
12291         if (oprref)
12292         {
12293                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12294                 free(oprref);
12295         }
12296
12297         if (strcmp(oprcanmerge, "t") == 0)
12298                 appendPQExpBufferStr(details, ",\n    MERGES");
12299
12300         if (strcmp(oprcanhash, "t") == 0)
12301                 appendPQExpBufferStr(details, ",\n    HASHES");
12302
12303         oprregproc = convertRegProcReference(fout, oprrest);
12304         if (oprregproc)
12305         {
12306                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12307                 free(oprregproc);
12308         }
12309
12310         oprregproc = convertRegProcReference(fout, oprjoin);
12311         if (oprregproc)
12312         {
12313                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12314                 free(oprregproc);
12315         }
12316
12317         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12318                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12319                                           oprid->data);
12320
12321         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12322                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12323                                           oprinfo->dobj.name, details->data);
12324
12325         if (dopt->binary_upgrade)
12326                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12327                                                                                 "OPERATOR", oprid->data,
12328                                                                                 oprinfo->dobj.namespace->dobj.name);
12329
12330         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12331                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12332                                          oprinfo->dobj.name,
12333                                          oprinfo->dobj.namespace->dobj.name,
12334                                          NULL,
12335                                          oprinfo->rolname,
12336                                          false, "OPERATOR", SECTION_PRE_DATA,
12337                                          q->data, delq->data, NULL,
12338                                          NULL, 0,
12339                                          NULL, NULL);
12340
12341         /* Dump Operator Comments */
12342         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12343                 dumpComment(fout, "OPERATOR", oprid->data,
12344                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12345                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12346
12347         PQclear(res);
12348
12349         destroyPQExpBuffer(query);
12350         destroyPQExpBuffer(q);
12351         destroyPQExpBuffer(delq);
12352         destroyPQExpBuffer(oprid);
12353         destroyPQExpBuffer(details);
12354 }
12355
12356 /*
12357  * Convert a function reference obtained from pg_operator
12358  *
12359  * Returns allocated string of what to print, or NULL if function references
12360  * is InvalidOid. Returned string is expected to be free'd by the caller.
12361  *
12362  * The input is a REGPROCEDURE display; we have to strip the argument-types
12363  * part.
12364  */
12365 static char *
12366 convertRegProcReference(Archive *fout, const char *proc)
12367 {
12368         char       *name;
12369         char       *paren;
12370         bool            inquote;
12371
12372         /* In all cases "-" means a null reference */
12373         if (strcmp(proc, "-") == 0)
12374                 return NULL;
12375
12376         name = pg_strdup(proc);
12377         /* find non-double-quoted left paren */
12378         inquote = false;
12379         for (paren = name; *paren; paren++)
12380         {
12381                 if (*paren == '(' && !inquote)
12382                 {
12383                         *paren = '\0';
12384                         break;
12385                 }
12386                 if (*paren == '"')
12387                         inquote = !inquote;
12388         }
12389         return name;
12390 }
12391
12392 /*
12393  * getFormattedOperatorName - retrieve the operator name for the
12394  * given operator OID (presented in string form).
12395  *
12396  * Returns an allocated string, or NULL if the given OID is invalid.
12397  * Caller is responsible for free'ing result string.
12398  *
12399  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12400  * useful in commands where the operator's argument types can be inferred from
12401  * context.  We always schema-qualify the name, though.  The predecessor to
12402  * this code tried to skip the schema qualification if possible, but that led
12403  * to wrong results in corner cases, such as if an operator and its negator
12404  * are in different schemas.
12405  */
12406 static char *
12407 getFormattedOperatorName(Archive *fout, const char *oproid)
12408 {
12409         OprInfo    *oprInfo;
12410
12411         /* In all cases "0" means a null reference */
12412         if (strcmp(oproid, "0") == 0)
12413                 return NULL;
12414
12415         oprInfo = findOprByOid(atooid(oproid));
12416         if (oprInfo == NULL)
12417         {
12418                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12419                                   oproid);
12420                 return NULL;
12421         }
12422
12423         return psprintf("OPERATOR(%s.%s)",
12424                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12425                                         oprInfo->dobj.name);
12426 }
12427
12428 /*
12429  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12430  *
12431  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12432  * argument lists of these functions are predetermined.  Note that the
12433  * caller should ensure we are in the proper schema, because the results
12434  * are search path dependent!
12435  */
12436 static char *
12437 convertTSFunction(Archive *fout, Oid funcOid)
12438 {
12439         char       *result;
12440         char            query[128];
12441         PGresult   *res;
12442
12443         snprintf(query, sizeof(query),
12444                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12445         res = ExecuteSqlQueryForSingleRow(fout, query);
12446
12447         result = pg_strdup(PQgetvalue(res, 0, 0));
12448
12449         PQclear(res);
12450
12451         return result;
12452 }
12453
12454 /*
12455  * dumpAccessMethod
12456  *        write out a single access method definition
12457  */
12458 static void
12459 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12460 {
12461         DumpOptions *dopt = fout->dopt;
12462         PQExpBuffer q;
12463         PQExpBuffer delq;
12464         char       *qamname;
12465
12466         /* Skip if not to be dumped */
12467         if (!aminfo->dobj.dump || dopt->dataOnly)
12468                 return;
12469
12470         q = createPQExpBuffer();
12471         delq = createPQExpBuffer();
12472
12473         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12474
12475         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12476
12477         switch (aminfo->amtype)
12478         {
12479                 case AMTYPE_INDEX:
12480                         appendPQExpBuffer(q, "TYPE INDEX ");
12481                         break;
12482                 default:
12483                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12484                                           aminfo->amtype, qamname);
12485                         destroyPQExpBuffer(q);
12486                         destroyPQExpBuffer(delq);
12487                         free(qamname);
12488                         return;
12489         }
12490
12491         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12492
12493         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12494                                           qamname);
12495
12496         if (dopt->binary_upgrade)
12497                 binary_upgrade_extension_member(q, &aminfo->dobj,
12498                                                                                 "ACCESS METHOD", qamname, NULL);
12499
12500         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12501                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12502                                          aminfo->dobj.name,
12503                                          NULL,
12504                                          NULL,
12505                                          "",
12506                                          false, "ACCESS METHOD", SECTION_PRE_DATA,
12507                                          q->data, delq->data, NULL,
12508                                          NULL, 0,
12509                                          NULL, NULL);
12510
12511         /* Dump Access Method Comments */
12512         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12513                 dumpComment(fout, "ACCESS METHOD", qamname,
12514                                         NULL, "",
12515                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12516
12517         destroyPQExpBuffer(q);
12518         destroyPQExpBuffer(delq);
12519         free(qamname);
12520 }
12521
12522 /*
12523  * dumpOpclass
12524  *        write out a single operator class definition
12525  */
12526 static void
12527 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12528 {
12529         DumpOptions *dopt = fout->dopt;
12530         PQExpBuffer query;
12531         PQExpBuffer q;
12532         PQExpBuffer delq;
12533         PQExpBuffer nameusing;
12534         PGresult   *res;
12535         int                     ntups;
12536         int                     i_opcintype;
12537         int                     i_opckeytype;
12538         int                     i_opcdefault;
12539         int                     i_opcfamily;
12540         int                     i_opcfamilyname;
12541         int                     i_opcfamilynsp;
12542         int                     i_amname;
12543         int                     i_amopstrategy;
12544         int                     i_amopreqcheck;
12545         int                     i_amopopr;
12546         int                     i_sortfamily;
12547         int                     i_sortfamilynsp;
12548         int                     i_amprocnum;
12549         int                     i_amproc;
12550         int                     i_amproclefttype;
12551         int                     i_amprocrighttype;
12552         char       *opcintype;
12553         char       *opckeytype;
12554         char       *opcdefault;
12555         char       *opcfamily;
12556         char       *opcfamilyname;
12557         char       *opcfamilynsp;
12558         char       *amname;
12559         char       *amopstrategy;
12560         char       *amopreqcheck;
12561         char       *amopopr;
12562         char       *sortfamily;
12563         char       *sortfamilynsp;
12564         char       *amprocnum;
12565         char       *amproc;
12566         char       *amproclefttype;
12567         char       *amprocrighttype;
12568         bool            needComma;
12569         int                     i;
12570
12571         /* Skip if not to be dumped */
12572         if (!opcinfo->dobj.dump || dopt->dataOnly)
12573                 return;
12574
12575         query = createPQExpBuffer();
12576         q = createPQExpBuffer();
12577         delq = createPQExpBuffer();
12578         nameusing = createPQExpBuffer();
12579
12580         /* Get additional fields from the pg_opclass row */
12581         if (fout->remoteVersion >= 80300)
12582         {
12583                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12584                                                   "opckeytype::pg_catalog.regtype, "
12585                                                   "opcdefault, opcfamily, "
12586                                                   "opfname AS opcfamilyname, "
12587                                                   "nspname AS opcfamilynsp, "
12588                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12589                                                   "FROM pg_catalog.pg_opclass c "
12590                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12591                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12592                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12593                                                   opcinfo->dobj.catId.oid);
12594         }
12595         else
12596         {
12597                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12598                                                   "opckeytype::pg_catalog.regtype, "
12599                                                   "opcdefault, NULL AS opcfamily, "
12600                                                   "NULL AS opcfamilyname, "
12601                                                   "NULL AS opcfamilynsp, "
12602                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12603                                                   "FROM pg_catalog.pg_opclass "
12604                                                   "WHERE oid = '%u'::pg_catalog.oid",
12605                                                   opcinfo->dobj.catId.oid);
12606         }
12607
12608         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12609
12610         i_opcintype = PQfnumber(res, "opcintype");
12611         i_opckeytype = PQfnumber(res, "opckeytype");
12612         i_opcdefault = PQfnumber(res, "opcdefault");
12613         i_opcfamily = PQfnumber(res, "opcfamily");
12614         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12615         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12616         i_amname = PQfnumber(res, "amname");
12617
12618         /* opcintype may still be needed after we PQclear res */
12619         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12620         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12621         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12622         /* opcfamily will still be needed after we PQclear res */
12623         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12624         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12625         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12626         /* amname will still be needed after we PQclear res */
12627         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12628
12629         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12630                                           fmtQualifiedDumpable(opcinfo));
12631         appendPQExpBuffer(delq, " USING %s;\n",
12632                                           fmtId(amname));
12633
12634         /* Build the fixed portion of the CREATE command */
12635         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12636                                           fmtQualifiedDumpable(opcinfo));
12637         if (strcmp(opcdefault, "t") == 0)
12638                 appendPQExpBufferStr(q, "DEFAULT ");
12639         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12640                                           opcintype,
12641                                           fmtId(amname));
12642         if (strlen(opcfamilyname) > 0)
12643         {
12644                 appendPQExpBufferStr(q, " FAMILY ");
12645                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12646                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12647         }
12648         appendPQExpBufferStr(q, " AS\n    ");
12649
12650         needComma = false;
12651
12652         if (strcmp(opckeytype, "-") != 0)
12653         {
12654                 appendPQExpBuffer(q, "STORAGE %s",
12655                                                   opckeytype);
12656                 needComma = true;
12657         }
12658
12659         PQclear(res);
12660
12661         /*
12662          * Now fetch and print the OPERATOR entries (pg_amop rows).
12663          *
12664          * Print only those opfamily members that are tied to the opclass by
12665          * pg_depend entries.
12666          *
12667          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12668          * older server's opclass in which it is used.  This is to avoid
12669          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12670          * older server and then reload into that old version.  This can go away
12671          * once 8.3 is so old as to not be of interest to anyone.
12672          */
12673         resetPQExpBuffer(query);
12674
12675         if (fout->remoteVersion >= 90100)
12676         {
12677                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12678                                                   "amopopr::pg_catalog.regoperator, "
12679                                                   "opfname AS sortfamily, "
12680                                                   "nspname AS sortfamilynsp "
12681                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12682                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12683                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12684                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12685                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12686                                                   "AND refobjid = '%u'::pg_catalog.oid "
12687                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12688                                                   "ORDER BY amopstrategy",
12689                                                   opcinfo->dobj.catId.oid,
12690                                                   opcfamily);
12691         }
12692         else if (fout->remoteVersion >= 80400)
12693         {
12694                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12695                                                   "amopopr::pg_catalog.regoperator, "
12696                                                   "NULL AS sortfamily, "
12697                                                   "NULL AS sortfamilynsp "
12698                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12699                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12700                                                   "AND refobjid = '%u'::pg_catalog.oid "
12701                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12702                                                   "AND objid = ao.oid "
12703                                                   "ORDER BY amopstrategy",
12704                                                   opcinfo->dobj.catId.oid);
12705         }
12706         else if (fout->remoteVersion >= 80300)
12707         {
12708                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12709                                                   "amopopr::pg_catalog.regoperator, "
12710                                                   "NULL AS sortfamily, "
12711                                                   "NULL AS sortfamilynsp "
12712                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12713                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12714                                                   "AND refobjid = '%u'::pg_catalog.oid "
12715                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12716                                                   "AND objid = ao.oid "
12717                                                   "ORDER BY amopstrategy",
12718                                                   opcinfo->dobj.catId.oid);
12719         }
12720         else
12721         {
12722                 /*
12723                  * Here, we print all entries since there are no opfamilies and hence
12724                  * no loose operators to worry about.
12725                  */
12726                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12727                                                   "amopopr::pg_catalog.regoperator, "
12728                                                   "NULL AS sortfamily, "
12729                                                   "NULL AS sortfamilynsp "
12730                                                   "FROM pg_catalog.pg_amop "
12731                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12732                                                   "ORDER BY amopstrategy",
12733                                                   opcinfo->dobj.catId.oid);
12734         }
12735
12736         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12737
12738         ntups = PQntuples(res);
12739
12740         i_amopstrategy = PQfnumber(res, "amopstrategy");
12741         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12742         i_amopopr = PQfnumber(res, "amopopr");
12743         i_sortfamily = PQfnumber(res, "sortfamily");
12744         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12745
12746         for (i = 0; i < ntups; i++)
12747         {
12748                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12749                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12750                 amopopr = PQgetvalue(res, i, i_amopopr);
12751                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12752                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12753
12754                 if (needComma)
12755                         appendPQExpBufferStr(q, " ,\n    ");
12756
12757                 appendPQExpBuffer(q, "OPERATOR %s %s",
12758                                                   amopstrategy, amopopr);
12759
12760                 if (strlen(sortfamily) > 0)
12761                 {
12762                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12763                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12764                         appendPQExpBufferStr(q, fmtId(sortfamily));
12765                 }
12766
12767                 if (strcmp(amopreqcheck, "t") == 0)
12768                         appendPQExpBufferStr(q, " RECHECK");
12769
12770                 needComma = true;
12771         }
12772
12773         PQclear(res);
12774
12775         /*
12776          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12777          *
12778          * Print only those opfamily members that are tied to the opclass by
12779          * pg_depend entries.
12780          *
12781          * We print the amproclefttype/amprocrighttype even though in most cases
12782          * the backend could deduce the right values, because of the corner case
12783          * of a btree sort support function for a cross-type comparison.  That's
12784          * only allowed in 9.2 and later, but for simplicity print them in all
12785          * versions that have the columns.
12786          */
12787         resetPQExpBuffer(query);
12788
12789         if (fout->remoteVersion >= 80300)
12790         {
12791                 appendPQExpBuffer(query, "SELECT amprocnum, "
12792                                                   "amproc::pg_catalog.regprocedure, "
12793                                                   "amproclefttype::pg_catalog.regtype, "
12794                                                   "amprocrighttype::pg_catalog.regtype "
12795                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12796                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12797                                                   "AND refobjid = '%u'::pg_catalog.oid "
12798                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12799                                                   "AND objid = ap.oid "
12800                                                   "ORDER BY amprocnum",
12801                                                   opcinfo->dobj.catId.oid);
12802         }
12803         else
12804         {
12805                 appendPQExpBuffer(query, "SELECT amprocnum, "
12806                                                   "amproc::pg_catalog.regprocedure, "
12807                                                   "'' AS amproclefttype, "
12808                                                   "'' AS amprocrighttype "
12809                                                   "FROM pg_catalog.pg_amproc "
12810                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12811                                                   "ORDER BY amprocnum",
12812                                                   opcinfo->dobj.catId.oid);
12813         }
12814
12815         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12816
12817         ntups = PQntuples(res);
12818
12819         i_amprocnum = PQfnumber(res, "amprocnum");
12820         i_amproc = PQfnumber(res, "amproc");
12821         i_amproclefttype = PQfnumber(res, "amproclefttype");
12822         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12823
12824         for (i = 0; i < ntups; i++)
12825         {
12826                 amprocnum = PQgetvalue(res, i, i_amprocnum);
12827                 amproc = PQgetvalue(res, i, i_amproc);
12828                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12829                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12830
12831                 if (needComma)
12832                         appendPQExpBufferStr(q, " ,\n    ");
12833
12834                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12835
12836                 if (*amproclefttype && *amprocrighttype)
12837                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12838
12839                 appendPQExpBuffer(q, " %s", amproc);
12840
12841                 needComma = true;
12842         }
12843
12844         PQclear(res);
12845
12846         /*
12847          * If needComma is still false it means we haven't added anything after
12848          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
12849          * clause with the same datatype.  This isn't sanctioned by the
12850          * documentation, but actually DefineOpClass will treat it as a no-op.
12851          */
12852         if (!needComma)
12853                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
12854
12855         appendPQExpBufferStr(q, ";\n");
12856
12857         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
12858         appendPQExpBuffer(nameusing, " USING %s",
12859                                           fmtId(amname));
12860
12861         if (dopt->binary_upgrade)
12862                 binary_upgrade_extension_member(q, &opcinfo->dobj,
12863                                                                                 "OPERATOR CLASS", nameusing->data,
12864                                                                                 opcinfo->dobj.namespace->dobj.name);
12865
12866         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12867                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12868                                          opcinfo->dobj.name,
12869                                          opcinfo->dobj.namespace->dobj.name,
12870                                          NULL,
12871                                          opcinfo->rolname,
12872                                          false, "OPERATOR CLASS", SECTION_PRE_DATA,
12873                                          q->data, delq->data, NULL,
12874                                          NULL, 0,
12875                                          NULL, NULL);
12876
12877         /* Dump Operator Class Comments */
12878         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12879                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
12880                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
12881                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
12882
12883         free(opcintype);
12884         free(opcfamily);
12885         free(amname);
12886         destroyPQExpBuffer(query);
12887         destroyPQExpBuffer(q);
12888         destroyPQExpBuffer(delq);
12889         destroyPQExpBuffer(nameusing);
12890 }
12891
12892 /*
12893  * dumpOpfamily
12894  *        write out a single operator family definition
12895  *
12896  * Note: this also dumps any "loose" operator members that aren't bound to a
12897  * specific opclass within the opfamily.
12898  */
12899 static void
12900 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
12901 {
12902         DumpOptions *dopt = fout->dopt;
12903         PQExpBuffer query;
12904         PQExpBuffer q;
12905         PQExpBuffer delq;
12906         PQExpBuffer nameusing;
12907         PGresult   *res;
12908         PGresult   *res_ops;
12909         PGresult   *res_procs;
12910         int                     ntups;
12911         int                     i_amname;
12912         int                     i_amopstrategy;
12913         int                     i_amopreqcheck;
12914         int                     i_amopopr;
12915         int                     i_sortfamily;
12916         int                     i_sortfamilynsp;
12917         int                     i_amprocnum;
12918         int                     i_amproc;
12919         int                     i_amproclefttype;
12920         int                     i_amprocrighttype;
12921         char       *amname;
12922         char       *amopstrategy;
12923         char       *amopreqcheck;
12924         char       *amopopr;
12925         char       *sortfamily;
12926         char       *sortfamilynsp;
12927         char       *amprocnum;
12928         char       *amproc;
12929         char       *amproclefttype;
12930         char       *amprocrighttype;
12931         bool            needComma;
12932         int                     i;
12933
12934         /* Skip if not to be dumped */
12935         if (!opfinfo->dobj.dump || dopt->dataOnly)
12936                 return;
12937
12938         query = createPQExpBuffer();
12939         q = createPQExpBuffer();
12940         delq = createPQExpBuffer();
12941         nameusing = createPQExpBuffer();
12942
12943         /*
12944          * Fetch only those opfamily members that are tied directly to the
12945          * opfamily by pg_depend entries.
12946          *
12947          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12948          * older server's opclass in which it is used.  This is to avoid
12949          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12950          * older server and then reload into that old version.  This can go away
12951          * once 8.3 is so old as to not be of interest to anyone.
12952          */
12953         if (fout->remoteVersion >= 90100)
12954         {
12955                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12956                                                   "amopopr::pg_catalog.regoperator, "
12957                                                   "opfname AS sortfamily, "
12958                                                   "nspname AS sortfamilynsp "
12959                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12960                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12961                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12962                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12963                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12964                                                   "AND refobjid = '%u'::pg_catalog.oid "
12965                                                   "AND amopfamily = '%u'::pg_catalog.oid "
12966                                                   "ORDER BY amopstrategy",
12967                                                   opfinfo->dobj.catId.oid,
12968                                                   opfinfo->dobj.catId.oid);
12969         }
12970         else if (fout->remoteVersion >= 80400)
12971         {
12972                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12973                                                   "amopopr::pg_catalog.regoperator, "
12974                                                   "NULL AS sortfamily, "
12975                                                   "NULL AS sortfamilynsp "
12976                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12977                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12978                                                   "AND refobjid = '%u'::pg_catalog.oid "
12979                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12980                                                   "AND objid = ao.oid "
12981                                                   "ORDER BY amopstrategy",
12982                                                   opfinfo->dobj.catId.oid);
12983         }
12984         else
12985         {
12986                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12987                                                   "amopopr::pg_catalog.regoperator, "
12988                                                   "NULL AS sortfamily, "
12989                                                   "NULL AS sortfamilynsp "
12990                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12991                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12992                                                   "AND refobjid = '%u'::pg_catalog.oid "
12993                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12994                                                   "AND objid = ao.oid "
12995                                                   "ORDER BY amopstrategy",
12996                                                   opfinfo->dobj.catId.oid);
12997         }
12998
12999         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13000
13001         resetPQExpBuffer(query);
13002
13003         appendPQExpBuffer(query, "SELECT amprocnum, "
13004                                           "amproc::pg_catalog.regprocedure, "
13005                                           "amproclefttype::pg_catalog.regtype, "
13006                                           "amprocrighttype::pg_catalog.regtype "
13007                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13008                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13009                                           "AND refobjid = '%u'::pg_catalog.oid "
13010                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13011                                           "AND objid = ap.oid "
13012                                           "ORDER BY amprocnum",
13013                                           opfinfo->dobj.catId.oid);
13014
13015         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13016
13017         /* Get additional fields from the pg_opfamily row */
13018         resetPQExpBuffer(query);
13019
13020         appendPQExpBuffer(query, "SELECT "
13021                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13022                                           "FROM pg_catalog.pg_opfamily "
13023                                           "WHERE oid = '%u'::pg_catalog.oid",
13024                                           opfinfo->dobj.catId.oid);
13025
13026         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13027
13028         i_amname = PQfnumber(res, "amname");
13029
13030         /* amname will still be needed after we PQclear res */
13031         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13032
13033         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13034                                           fmtQualifiedDumpable(opfinfo));
13035         appendPQExpBuffer(delq, " USING %s;\n",
13036                                           fmtId(amname));
13037
13038         /* Build the fixed portion of the CREATE command */
13039         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13040                                           fmtQualifiedDumpable(opfinfo));
13041         appendPQExpBuffer(q, " USING %s;\n",
13042                                           fmtId(amname));
13043
13044         PQclear(res);
13045
13046         /* Do we need an ALTER to add loose members? */
13047         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13048         {
13049                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13050                                                   fmtQualifiedDumpable(opfinfo));
13051                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13052                                                   fmtId(amname));
13053
13054                 needComma = false;
13055
13056                 /*
13057                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13058                  */
13059                 ntups = PQntuples(res_ops);
13060
13061                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13062                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13063                 i_amopopr = PQfnumber(res_ops, "amopopr");
13064                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13065                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13066
13067                 for (i = 0; i < ntups; i++)
13068                 {
13069                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13070                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13071                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13072                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13073                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13074
13075                         if (needComma)
13076                                 appendPQExpBufferStr(q, " ,\n    ");
13077
13078                         appendPQExpBuffer(q, "OPERATOR %s %s",
13079                                                           amopstrategy, amopopr);
13080
13081                         if (strlen(sortfamily) > 0)
13082                         {
13083                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13084                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13085                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13086                         }
13087
13088                         if (strcmp(amopreqcheck, "t") == 0)
13089                                 appendPQExpBufferStr(q, " RECHECK");
13090
13091                         needComma = true;
13092                 }
13093
13094                 /*
13095                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13096                  */
13097                 ntups = PQntuples(res_procs);
13098
13099                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13100                 i_amproc = PQfnumber(res_procs, "amproc");
13101                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13102                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13103
13104                 for (i = 0; i < ntups; i++)
13105                 {
13106                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13107                         amproc = PQgetvalue(res_procs, i, i_amproc);
13108                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13109                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13110
13111                         if (needComma)
13112                                 appendPQExpBufferStr(q, " ,\n    ");
13113
13114                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13115                                                           amprocnum, amproclefttype, amprocrighttype,
13116                                                           amproc);
13117
13118                         needComma = true;
13119                 }
13120
13121                 appendPQExpBufferStr(q, ";\n");
13122         }
13123
13124         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13125         appendPQExpBuffer(nameusing, " USING %s",
13126                                           fmtId(amname));
13127
13128         if (dopt->binary_upgrade)
13129                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13130                                                                                 "OPERATOR FAMILY", nameusing->data,
13131                                                                                 opfinfo->dobj.namespace->dobj.name);
13132
13133         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13134                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13135                                          opfinfo->dobj.name,
13136                                          opfinfo->dobj.namespace->dobj.name,
13137                                          NULL,
13138                                          opfinfo->rolname,
13139                                          false, "OPERATOR FAMILY", SECTION_PRE_DATA,
13140                                          q->data, delq->data, NULL,
13141                                          NULL, 0,
13142                                          NULL, NULL);
13143
13144         /* Dump Operator Family Comments */
13145         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13146                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13147                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13148                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13149
13150         free(amname);
13151         PQclear(res_ops);
13152         PQclear(res_procs);
13153         destroyPQExpBuffer(query);
13154         destroyPQExpBuffer(q);
13155         destroyPQExpBuffer(delq);
13156         destroyPQExpBuffer(nameusing);
13157 }
13158
13159 /*
13160  * dumpCollation
13161  *        write out a single collation definition
13162  */
13163 static void
13164 dumpCollation(Archive *fout, CollInfo *collinfo)
13165 {
13166         DumpOptions *dopt = fout->dopt;
13167         PQExpBuffer query;
13168         PQExpBuffer q;
13169         PQExpBuffer delq;
13170         char       *qcollname;
13171         PGresult   *res;
13172         int                     i_collprovider;
13173         int                     i_collcollate;
13174         int                     i_collctype;
13175         const char *collprovider;
13176         const char *collcollate;
13177         const char *collctype;
13178
13179         /* Skip if not to be dumped */
13180         if (!collinfo->dobj.dump || dopt->dataOnly)
13181                 return;
13182
13183         query = createPQExpBuffer();
13184         q = createPQExpBuffer();
13185         delq = createPQExpBuffer();
13186
13187         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13188
13189         /* Get collation-specific details */
13190         if (fout->remoteVersion >= 100000)
13191                 appendPQExpBuffer(query, "SELECT "
13192                                                   "collprovider, "
13193                                                   "collcollate, "
13194                                                   "collctype, "
13195                                                   "collversion "
13196                                                   "FROM pg_catalog.pg_collation c "
13197                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13198                                                   collinfo->dobj.catId.oid);
13199         else
13200                 appendPQExpBuffer(query, "SELECT "
13201                                                   "'c' AS collprovider, "
13202                                                   "collcollate, "
13203                                                   "collctype, "
13204                                                   "NULL AS collversion "
13205                                                   "FROM pg_catalog.pg_collation c "
13206                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13207                                                   collinfo->dobj.catId.oid);
13208
13209         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13210
13211         i_collprovider = PQfnumber(res, "collprovider");
13212         i_collcollate = PQfnumber(res, "collcollate");
13213         i_collctype = PQfnumber(res, "collctype");
13214
13215         collprovider = PQgetvalue(res, 0, i_collprovider);
13216         collcollate = PQgetvalue(res, 0, i_collcollate);
13217         collctype = PQgetvalue(res, 0, i_collctype);
13218
13219         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13220                                           fmtQualifiedDumpable(collinfo));
13221
13222         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13223                                           fmtQualifiedDumpable(collinfo));
13224
13225         appendPQExpBufferStr(q, "provider = ");
13226         if (collprovider[0] == 'c')
13227                 appendPQExpBufferStr(q, "libc");
13228         else if (collprovider[0] == 'i')
13229                 appendPQExpBufferStr(q, "icu");
13230         else if (collprovider[0] == 'd')
13231                 /* to allow dumping pg_catalog; not accepted on input */
13232                 appendPQExpBufferStr(q, "default");
13233         else
13234                 exit_horribly(NULL,
13235                                           "unrecognized collation provider: %s\n",
13236                                           collprovider);
13237
13238         if (strcmp(collcollate, collctype) == 0)
13239         {
13240                 appendPQExpBufferStr(q, ", locale = ");
13241                 appendStringLiteralAH(q, collcollate, fout);
13242         }
13243         else
13244         {
13245                 appendPQExpBufferStr(q, ", lc_collate = ");
13246                 appendStringLiteralAH(q, collcollate, fout);
13247                 appendPQExpBufferStr(q, ", lc_ctype = ");
13248                 appendStringLiteralAH(q, collctype, fout);
13249         }
13250
13251         /*
13252          * For binary upgrade, carry over the collation version.  For normal
13253          * dump/restore, omit the version, so that it is computed upon restore.
13254          */
13255         if (dopt->binary_upgrade)
13256         {
13257                 int                     i_collversion;
13258
13259                 i_collversion = PQfnumber(res, "collversion");
13260                 if (!PQgetisnull(res, 0, i_collversion))
13261                 {
13262                         appendPQExpBufferStr(q, ", version = ");
13263                         appendStringLiteralAH(q,
13264                                                                   PQgetvalue(res, 0, i_collversion),
13265                                                                   fout);
13266                 }
13267         }
13268
13269         appendPQExpBufferStr(q, ");\n");
13270
13271         if (dopt->binary_upgrade)
13272                 binary_upgrade_extension_member(q, &collinfo->dobj,
13273                                                                                 "COLLATION", qcollname,
13274                                                                                 collinfo->dobj.namespace->dobj.name);
13275
13276         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13277                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13278                                          collinfo->dobj.name,
13279                                          collinfo->dobj.namespace->dobj.name,
13280                                          NULL,
13281                                          collinfo->rolname,
13282                                          false, "COLLATION", SECTION_PRE_DATA,
13283                                          q->data, delq->data, NULL,
13284                                          NULL, 0,
13285                                          NULL, NULL);
13286
13287         /* Dump Collation Comments */
13288         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13289                 dumpComment(fout, "COLLATION", qcollname,
13290                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13291                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13292
13293         PQclear(res);
13294
13295         destroyPQExpBuffer(query);
13296         destroyPQExpBuffer(q);
13297         destroyPQExpBuffer(delq);
13298         free(qcollname);
13299 }
13300
13301 /*
13302  * dumpConversion
13303  *        write out a single conversion definition
13304  */
13305 static void
13306 dumpConversion(Archive *fout, ConvInfo *convinfo)
13307 {
13308         DumpOptions *dopt = fout->dopt;
13309         PQExpBuffer query;
13310         PQExpBuffer q;
13311         PQExpBuffer delq;
13312         char       *qconvname;
13313         PGresult   *res;
13314         int                     i_conforencoding;
13315         int                     i_contoencoding;
13316         int                     i_conproc;
13317         int                     i_condefault;
13318         const char *conforencoding;
13319         const char *contoencoding;
13320         const char *conproc;
13321         bool            condefault;
13322
13323         /* Skip if not to be dumped */
13324         if (!convinfo->dobj.dump || dopt->dataOnly)
13325                 return;
13326
13327         query = createPQExpBuffer();
13328         q = createPQExpBuffer();
13329         delq = createPQExpBuffer();
13330
13331         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13332
13333         /* Get conversion-specific details */
13334         appendPQExpBuffer(query, "SELECT "
13335                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13336                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13337                                           "conproc, condefault "
13338                                           "FROM pg_catalog.pg_conversion c "
13339                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13340                                           convinfo->dobj.catId.oid);
13341
13342         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13343
13344         i_conforencoding = PQfnumber(res, "conforencoding");
13345         i_contoencoding = PQfnumber(res, "contoencoding");
13346         i_conproc = PQfnumber(res, "conproc");
13347         i_condefault = PQfnumber(res, "condefault");
13348
13349         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13350         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13351         conproc = PQgetvalue(res, 0, i_conproc);
13352         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13353
13354         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13355                                           fmtQualifiedDumpable(convinfo));
13356
13357         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13358                                           (condefault) ? "DEFAULT " : "",
13359                                           fmtQualifiedDumpable(convinfo));
13360         appendStringLiteralAH(q, conforencoding, fout);
13361         appendPQExpBufferStr(q, " TO ");
13362         appendStringLiteralAH(q, contoencoding, fout);
13363         /* regproc output is already sufficiently quoted */
13364         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13365
13366         if (dopt->binary_upgrade)
13367                 binary_upgrade_extension_member(q, &convinfo->dobj,
13368                                                                                 "CONVERSION", qconvname,
13369                                                                                 convinfo->dobj.namespace->dobj.name);
13370
13371         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13372                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13373                                          convinfo->dobj.name,
13374                                          convinfo->dobj.namespace->dobj.name,
13375                                          NULL,
13376                                          convinfo->rolname,
13377                                          false, "CONVERSION", SECTION_PRE_DATA,
13378                                          q->data, delq->data, NULL,
13379                                          NULL, 0,
13380                                          NULL, NULL);
13381
13382         /* Dump Conversion Comments */
13383         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13384                 dumpComment(fout, "CONVERSION", qconvname,
13385                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13386                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13387
13388         PQclear(res);
13389
13390         destroyPQExpBuffer(query);
13391         destroyPQExpBuffer(q);
13392         destroyPQExpBuffer(delq);
13393         free(qconvname);
13394 }
13395
13396 /*
13397  * format_aggregate_signature: generate aggregate name and argument list
13398  *
13399  * The argument type names are qualified if needed.  The aggregate name
13400  * is never qualified.
13401  */
13402 static char *
13403 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13404 {
13405         PQExpBufferData buf;
13406         int                     j;
13407
13408         initPQExpBuffer(&buf);
13409         if (honor_quotes)
13410                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13411         else
13412                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13413
13414         if (agginfo->aggfn.nargs == 0)
13415                 appendPQExpBuffer(&buf, "(*)");
13416         else
13417         {
13418                 appendPQExpBufferChar(&buf, '(');
13419                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13420                 {
13421                         char       *typname;
13422
13423                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13424                                                                                    zeroAsOpaque);
13425
13426                         appendPQExpBuffer(&buf, "%s%s",
13427                                                           (j > 0) ? ", " : "",
13428                                                           typname);
13429                         free(typname);
13430                 }
13431                 appendPQExpBufferChar(&buf, ')');
13432         }
13433         return buf.data;
13434 }
13435
13436 /*
13437  * dumpAgg
13438  *        write out a single aggregate definition
13439  */
13440 static void
13441 dumpAgg(Archive *fout, AggInfo *agginfo)
13442 {
13443         DumpOptions *dopt = fout->dopt;
13444         PQExpBuffer query;
13445         PQExpBuffer q;
13446         PQExpBuffer delq;
13447         PQExpBuffer details;
13448         char       *aggsig;                     /* identity signature */
13449         char       *aggfullsig = NULL;  /* full signature */
13450         char       *aggsig_tag;
13451         PGresult   *res;
13452         int                     i_aggtransfn;
13453         int                     i_aggfinalfn;
13454         int                     i_aggcombinefn;
13455         int                     i_aggserialfn;
13456         int                     i_aggdeserialfn;
13457         int                     i_aggmtransfn;
13458         int                     i_aggminvtransfn;
13459         int                     i_aggmfinalfn;
13460         int                     i_aggfinalextra;
13461         int                     i_aggmfinalextra;
13462         int                     i_aggfinalmodify;
13463         int                     i_aggmfinalmodify;
13464         int                     i_aggsortop;
13465         int                     i_aggkind;
13466         int                     i_aggtranstype;
13467         int                     i_aggtransspace;
13468         int                     i_aggmtranstype;
13469         int                     i_aggmtransspace;
13470         int                     i_agginitval;
13471         int                     i_aggminitval;
13472         int                     i_convertok;
13473         int                     i_proparallel;
13474         const char *aggtransfn;
13475         const char *aggfinalfn;
13476         const char *aggcombinefn;
13477         const char *aggserialfn;
13478         const char *aggdeserialfn;
13479         const char *aggmtransfn;
13480         const char *aggminvtransfn;
13481         const char *aggmfinalfn;
13482         bool            aggfinalextra;
13483         bool            aggmfinalextra;
13484         char            aggfinalmodify;
13485         char            aggmfinalmodify;
13486         const char *aggsortop;
13487         char       *aggsortconvop;
13488         char            aggkind;
13489         const char *aggtranstype;
13490         const char *aggtransspace;
13491         const char *aggmtranstype;
13492         const char *aggmtransspace;
13493         const char *agginitval;
13494         const char *aggminitval;
13495         bool            convertok;
13496         const char *proparallel;
13497         char            defaultfinalmodify;
13498
13499         /* Skip if not to be dumped */
13500         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13501                 return;
13502
13503         query = createPQExpBuffer();
13504         q = createPQExpBuffer();
13505         delq = createPQExpBuffer();
13506         details = createPQExpBuffer();
13507
13508         /* Get aggregate-specific details */
13509         if (fout->remoteVersion >= 110000)
13510         {
13511                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13512                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13513                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13514                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13515                                                   "aggfinalextra, aggmfinalextra, "
13516                                                   "aggfinalmodify, aggmfinalmodify, "
13517                                                   "aggsortop, "
13518                                                   "aggkind, "
13519                                                   "aggtransspace, agginitval, "
13520                                                   "aggmtransspace, aggminitval, "
13521                                                   "true AS convertok, "
13522                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13523                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13524                                                   "p.proparallel "
13525                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13526                                                   "WHERE a.aggfnoid = p.oid "
13527                                                   "AND p.oid = '%u'::pg_catalog.oid",
13528                                                   agginfo->aggfn.dobj.catId.oid);
13529         }
13530         else if (fout->remoteVersion >= 90600)
13531         {
13532                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13533                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13534                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13535                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13536                                                   "aggfinalextra, aggmfinalextra, "
13537                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13538                                                   "aggsortop, "
13539                                                   "aggkind, "
13540                                                   "aggtransspace, agginitval, "
13541                                                   "aggmtransspace, aggminitval, "
13542                                                   "true AS convertok, "
13543                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13544                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13545                                                   "p.proparallel "
13546                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13547                                                   "WHERE a.aggfnoid = p.oid "
13548                                                   "AND p.oid = '%u'::pg_catalog.oid",
13549                                                   agginfo->aggfn.dobj.catId.oid);
13550         }
13551         else if (fout->remoteVersion >= 90400)
13552         {
13553                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13554                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13555                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13556                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13557                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13558                                                   "aggfinalextra, aggmfinalextra, "
13559                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13560                                                   "aggsortop, "
13561                                                   "aggkind, "
13562                                                   "aggtransspace, agginitval, "
13563                                                   "aggmtransspace, aggminitval, "
13564                                                   "true AS convertok, "
13565                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13566                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13567                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13568                                                   "WHERE a.aggfnoid = p.oid "
13569                                                   "AND p.oid = '%u'::pg_catalog.oid",
13570                                                   agginfo->aggfn.dobj.catId.oid);
13571         }
13572         else if (fout->remoteVersion >= 80400)
13573         {
13574                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13575                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13576                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13577                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13578                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13579                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13580                                                   "false AS aggmfinalextra, "
13581                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13582                                                   "aggsortop, "
13583                                                   "'n' AS aggkind, "
13584                                                   "0 AS aggtransspace, agginitval, "
13585                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13586                                                   "true AS convertok, "
13587                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13588                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13589                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13590                                                   "WHERE a.aggfnoid = p.oid "
13591                                                   "AND p.oid = '%u'::pg_catalog.oid",
13592                                                   agginfo->aggfn.dobj.catId.oid);
13593         }
13594         else if (fout->remoteVersion >= 80100)
13595         {
13596                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13597                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13598                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13599                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13600                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13601                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13602                                                   "false AS aggmfinalextra, "
13603                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13604                                                   "aggsortop, "
13605                                                   "'n' AS aggkind, "
13606                                                   "0 AS aggtransspace, agginitval, "
13607                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13608                                                   "true AS convertok "
13609                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13610                                                   "WHERE a.aggfnoid = p.oid "
13611                                                   "AND p.oid = '%u'::pg_catalog.oid",
13612                                                   agginfo->aggfn.dobj.catId.oid);
13613         }
13614         else
13615         {
13616                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13617                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13618                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13619                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13620                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13621                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13622                                                   "false AS aggmfinalextra, "
13623                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13624                                                   "0 AS aggsortop, "
13625                                                   "'n' AS aggkind, "
13626                                                   "0 AS aggtransspace, agginitval, "
13627                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13628                                                   "true AS convertok "
13629                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13630                                                   "WHERE a.aggfnoid = p.oid "
13631                                                   "AND p.oid = '%u'::pg_catalog.oid",
13632                                                   agginfo->aggfn.dobj.catId.oid);
13633         }
13634
13635         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13636
13637         i_aggtransfn = PQfnumber(res, "aggtransfn");
13638         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13639         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13640         i_aggserialfn = PQfnumber(res, "aggserialfn");
13641         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13642         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13643         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13644         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13645         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13646         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13647         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13648         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13649         i_aggsortop = PQfnumber(res, "aggsortop");
13650         i_aggkind = PQfnumber(res, "aggkind");
13651         i_aggtranstype = PQfnumber(res, "aggtranstype");
13652         i_aggtransspace = PQfnumber(res, "aggtransspace");
13653         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13654         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13655         i_agginitval = PQfnumber(res, "agginitval");
13656         i_aggminitval = PQfnumber(res, "aggminitval");
13657         i_convertok = PQfnumber(res, "convertok");
13658         i_proparallel = PQfnumber(res, "proparallel");
13659
13660         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13661         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13662         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13663         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13664         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13665         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13666         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13667         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13668         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13669         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13670         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13671         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13672         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13673         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13674         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13675         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13676         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13677         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13678         agginitval = PQgetvalue(res, 0, i_agginitval);
13679         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13680         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13681
13682         if (fout->remoteVersion >= 80400)
13683         {
13684                 /* 8.4 or later; we rely on server-side code for most of the work */
13685                 char       *funcargs;
13686                 char       *funciargs;
13687
13688                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13689                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13690                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13691                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13692         }
13693         else
13694                 /* pre-8.4, do it ourselves */
13695                 aggsig = format_aggregate_signature(agginfo, fout, true);
13696
13697         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13698
13699         if (i_proparallel != -1)
13700                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13701         else
13702                 proparallel = NULL;
13703
13704         if (!convertok)
13705         {
13706                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13707                                   aggsig);
13708
13709                 if (aggfullsig)
13710                         free(aggfullsig);
13711
13712                 free(aggsig);
13713
13714                 return;
13715         }
13716
13717         /* identify default modify flag for aggkind (must match DefineAggregate) */
13718         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13719         /* replace omitted flags for old versions */
13720         if (aggfinalmodify == '0')
13721                 aggfinalmodify = defaultfinalmodify;
13722         if (aggmfinalmodify == '0')
13723                 aggmfinalmodify = defaultfinalmodify;
13724
13725         /* regproc and regtype output is already sufficiently quoted */
13726         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13727                                           aggtransfn, aggtranstype);
13728
13729         if (strcmp(aggtransspace, "0") != 0)
13730         {
13731                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13732                                                   aggtransspace);
13733         }
13734
13735         if (!PQgetisnull(res, 0, i_agginitval))
13736         {
13737                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13738                 appendStringLiteralAH(details, agginitval, fout);
13739         }
13740
13741         if (strcmp(aggfinalfn, "-") != 0)
13742         {
13743                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13744                                                   aggfinalfn);
13745                 if (aggfinalextra)
13746                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13747                 if (aggfinalmodify != defaultfinalmodify)
13748                 {
13749                         switch (aggfinalmodify)
13750                         {
13751                                 case AGGMODIFY_READ_ONLY:
13752                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13753                                         break;
13754                                 case AGGMODIFY_SHARABLE:
13755                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHARABLE");
13756                                         break;
13757                                 case AGGMODIFY_READ_WRITE:
13758                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13759                                         break;
13760                                 default:
13761                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
13762                                                                   agginfo->aggfn.dobj.name);
13763                                         break;
13764                         }
13765                 }
13766         }
13767
13768         if (strcmp(aggcombinefn, "-") != 0)
13769                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13770
13771         if (strcmp(aggserialfn, "-") != 0)
13772                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13773
13774         if (strcmp(aggdeserialfn, "-") != 0)
13775                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13776
13777         if (strcmp(aggmtransfn, "-") != 0)
13778         {
13779                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13780                                                   aggmtransfn,
13781                                                   aggminvtransfn,
13782                                                   aggmtranstype);
13783         }
13784
13785         if (strcmp(aggmtransspace, "0") != 0)
13786         {
13787                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
13788                                                   aggmtransspace);
13789         }
13790
13791         if (!PQgetisnull(res, 0, i_aggminitval))
13792         {
13793                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
13794                 appendStringLiteralAH(details, aggminitval, fout);
13795         }
13796
13797         if (strcmp(aggmfinalfn, "-") != 0)
13798         {
13799                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
13800                                                   aggmfinalfn);
13801                 if (aggmfinalextra)
13802                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
13803                 if (aggmfinalmodify != defaultfinalmodify)
13804                 {
13805                         switch (aggmfinalmodify)
13806                         {
13807                                 case AGGMODIFY_READ_ONLY:
13808                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
13809                                         break;
13810                                 case AGGMODIFY_SHARABLE:
13811                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHARABLE");
13812                                         break;
13813                                 case AGGMODIFY_READ_WRITE:
13814                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
13815                                         break;
13816                                 default:
13817                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
13818                                                                   agginfo->aggfn.dobj.name);
13819                                         break;
13820                         }
13821                 }
13822         }
13823
13824         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
13825         if (aggsortconvop)
13826         {
13827                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
13828                                                   aggsortconvop);
13829                 free(aggsortconvop);
13830         }
13831
13832         if (aggkind == AGGKIND_HYPOTHETICAL)
13833                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
13834
13835         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13836         {
13837                 if (proparallel[0] == PROPARALLEL_SAFE)
13838                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
13839                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13840                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
13841                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13842                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13843                                                   agginfo->aggfn.dobj.name);
13844         }
13845
13846         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13847                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13848                                           aggsig);
13849
13850         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
13851                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13852                                           aggfullsig ? aggfullsig : aggsig, details->data);
13853
13854         if (dopt->binary_upgrade)
13855                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
13856                                                                                 "AGGREGATE", aggsig,
13857                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
13858
13859         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13860                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13861                                          agginfo->aggfn.dobj.dumpId,
13862                                          aggsig_tag,
13863                                          agginfo->aggfn.dobj.namespace->dobj.name,
13864                                          NULL,
13865                                          agginfo->aggfn.rolname,
13866                                          false, "AGGREGATE", SECTION_PRE_DATA,
13867                                          q->data, delq->data, NULL,
13868                                          NULL, 0,
13869                                          NULL, NULL);
13870
13871         /* Dump Aggregate Comments */
13872         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13873                 dumpComment(fout, "AGGREGATE", aggsig,
13874                                         agginfo->aggfn.dobj.namespace->dobj.name,
13875                                         agginfo->aggfn.rolname,
13876                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13877
13878         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
13879                 dumpSecLabel(fout, "AGGREGATE", aggsig,
13880                                          agginfo->aggfn.dobj.namespace->dobj.name,
13881                                          agginfo->aggfn.rolname,
13882                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13883
13884         /*
13885          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
13886          * command look like a function's GRANT; in particular this affects the
13887          * syntax for zero-argument aggregates and ordered-set aggregates.
13888          */
13889         free(aggsig);
13890
13891         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
13892
13893         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
13894                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
13895                                 "FUNCTION", aggsig, NULL,
13896                                 agginfo->aggfn.dobj.namespace->dobj.name,
13897                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
13898                                 agginfo->aggfn.rproacl,
13899                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
13900
13901         free(aggsig);
13902         if (aggfullsig)
13903                 free(aggfullsig);
13904         free(aggsig_tag);
13905
13906         PQclear(res);
13907
13908         destroyPQExpBuffer(query);
13909         destroyPQExpBuffer(q);
13910         destroyPQExpBuffer(delq);
13911         destroyPQExpBuffer(details);
13912 }
13913
13914 /*
13915  * dumpTSParser
13916  *        write out a single text search parser
13917  */
13918 static void
13919 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
13920 {
13921         DumpOptions *dopt = fout->dopt;
13922         PQExpBuffer q;
13923         PQExpBuffer delq;
13924         char       *qprsname;
13925
13926         /* Skip if not to be dumped */
13927         if (!prsinfo->dobj.dump || dopt->dataOnly)
13928                 return;
13929
13930         q = createPQExpBuffer();
13931         delq = createPQExpBuffer();
13932
13933         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
13934
13935         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
13936                                           fmtQualifiedDumpable(prsinfo));
13937
13938         appendPQExpBuffer(q, "    START = %s,\n",
13939                                           convertTSFunction(fout, prsinfo->prsstart));
13940         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
13941                                           convertTSFunction(fout, prsinfo->prstoken));
13942         appendPQExpBuffer(q, "    END = %s,\n",
13943                                           convertTSFunction(fout, prsinfo->prsend));
13944         if (prsinfo->prsheadline != InvalidOid)
13945                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
13946                                                   convertTSFunction(fout, prsinfo->prsheadline));
13947         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
13948                                           convertTSFunction(fout, prsinfo->prslextype));
13949
13950         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
13951                                           fmtQualifiedDumpable(prsinfo));
13952
13953         if (dopt->binary_upgrade)
13954                 binary_upgrade_extension_member(q, &prsinfo->dobj,
13955                                                                                 "TEXT SEARCH PARSER", qprsname,
13956                                                                                 prsinfo->dobj.namespace->dobj.name);
13957
13958         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13959                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
13960                                          prsinfo->dobj.name,
13961                                          prsinfo->dobj.namespace->dobj.name,
13962                                          NULL,
13963                                          "",
13964                                          false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
13965                                          q->data, delq->data, NULL,
13966                                          NULL, 0,
13967                                          NULL, NULL);
13968
13969         /* Dump Parser Comments */
13970         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13971                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
13972                                         prsinfo->dobj.namespace->dobj.name, "",
13973                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
13974
13975         destroyPQExpBuffer(q);
13976         destroyPQExpBuffer(delq);
13977         free(qprsname);
13978 }
13979
13980 /*
13981  * dumpTSDictionary
13982  *        write out a single text search dictionary
13983  */
13984 static void
13985 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
13986 {
13987         DumpOptions *dopt = fout->dopt;
13988         PQExpBuffer q;
13989         PQExpBuffer delq;
13990         PQExpBuffer query;
13991         char       *qdictname;
13992         PGresult   *res;
13993         char       *nspname;
13994         char       *tmplname;
13995
13996         /* Skip if not to be dumped */
13997         if (!dictinfo->dobj.dump || dopt->dataOnly)
13998                 return;
13999
14000         q = createPQExpBuffer();
14001         delq = createPQExpBuffer();
14002         query = createPQExpBuffer();
14003
14004         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14005
14006         /* Fetch name and namespace of the dictionary's template */
14007         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14008                                           "FROM pg_ts_template p, pg_namespace n "
14009                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14010                                           dictinfo->dicttemplate);
14011         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14012         nspname = PQgetvalue(res, 0, 0);
14013         tmplname = PQgetvalue(res, 0, 1);
14014
14015         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14016                                           fmtQualifiedDumpable(dictinfo));
14017
14018         appendPQExpBufferStr(q, "    TEMPLATE = ");
14019         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14020         appendPQExpBufferStr(q, fmtId(tmplname));
14021
14022         PQclear(res);
14023
14024         /* the dictinitoption can be dumped straight into the command */
14025         if (dictinfo->dictinitoption)
14026                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14027
14028         appendPQExpBufferStr(q, " );\n");
14029
14030         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14031                                           fmtQualifiedDumpable(dictinfo));
14032
14033         if (dopt->binary_upgrade)
14034                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14035                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14036                                                                                 dictinfo->dobj.namespace->dobj.name);
14037
14038         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14039                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14040                                          dictinfo->dobj.name,
14041                                          dictinfo->dobj.namespace->dobj.name,
14042                                          NULL,
14043                                          dictinfo->rolname,
14044                                          false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
14045                                          q->data, delq->data, NULL,
14046                                          NULL, 0,
14047                                          NULL, NULL);
14048
14049         /* Dump Dictionary Comments */
14050         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14051                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14052                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14053                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14054
14055         destroyPQExpBuffer(q);
14056         destroyPQExpBuffer(delq);
14057         destroyPQExpBuffer(query);
14058         free(qdictname);
14059 }
14060
14061 /*
14062  * dumpTSTemplate
14063  *        write out a single text search template
14064  */
14065 static void
14066 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14067 {
14068         DumpOptions *dopt = fout->dopt;
14069         PQExpBuffer q;
14070         PQExpBuffer delq;
14071         char       *qtmplname;
14072
14073         /* Skip if not to be dumped */
14074         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14075                 return;
14076
14077         q = createPQExpBuffer();
14078         delq = createPQExpBuffer();
14079
14080         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14081
14082         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14083                                           fmtQualifiedDumpable(tmplinfo));
14084
14085         if (tmplinfo->tmplinit != InvalidOid)
14086                 appendPQExpBuffer(q, "    INIT = %s,\n",
14087                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14088         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14089                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14090
14091         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14092                                           fmtQualifiedDumpable(tmplinfo));
14093
14094         if (dopt->binary_upgrade)
14095                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14096                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14097                                                                                 tmplinfo->dobj.namespace->dobj.name);
14098
14099         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14100                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14101                                          tmplinfo->dobj.name,
14102                                          tmplinfo->dobj.namespace->dobj.name,
14103                                          NULL,
14104                                          "",
14105                                          false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
14106                                          q->data, delq->data, NULL,
14107                                          NULL, 0,
14108                                          NULL, NULL);
14109
14110         /* Dump Template Comments */
14111         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14112                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14113                                         tmplinfo->dobj.namespace->dobj.name, "",
14114                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14115
14116         destroyPQExpBuffer(q);
14117         destroyPQExpBuffer(delq);
14118         free(qtmplname);
14119 }
14120
14121 /*
14122  * dumpTSConfig
14123  *        write out a single text search configuration
14124  */
14125 static void
14126 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14127 {
14128         DumpOptions *dopt = fout->dopt;
14129         PQExpBuffer q;
14130         PQExpBuffer delq;
14131         PQExpBuffer query;
14132         char       *qcfgname;
14133         PGresult   *res;
14134         char       *nspname;
14135         char       *prsname;
14136         int                     ntups,
14137                                 i;
14138         int                     i_tokenname;
14139         int                     i_dictname;
14140
14141         /* Skip if not to be dumped */
14142         if (!cfginfo->dobj.dump || dopt->dataOnly)
14143                 return;
14144
14145         q = createPQExpBuffer();
14146         delq = createPQExpBuffer();
14147         query = createPQExpBuffer();
14148
14149         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14150
14151         /* Fetch name and namespace of the config's parser */
14152         appendPQExpBuffer(query, "SELECT nspname, prsname "
14153                                           "FROM pg_ts_parser p, pg_namespace n "
14154                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14155                                           cfginfo->cfgparser);
14156         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14157         nspname = PQgetvalue(res, 0, 0);
14158         prsname = PQgetvalue(res, 0, 1);
14159
14160         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14161                                           fmtQualifiedDumpable(cfginfo));
14162
14163         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14164         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14165
14166         PQclear(res);
14167
14168         resetPQExpBuffer(query);
14169         appendPQExpBuffer(query,
14170                                           "SELECT\n"
14171                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14172                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14173                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14174                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14175                                           "WHERE m.mapcfg = '%u'\n"
14176                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14177                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14178
14179         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14180         ntups = PQntuples(res);
14181
14182         i_tokenname = PQfnumber(res, "tokenname");
14183         i_dictname = PQfnumber(res, "dictname");
14184
14185         for (i = 0; i < ntups; i++)
14186         {
14187                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14188                 char       *dictname = PQgetvalue(res, i, i_dictname);
14189
14190                 if (i == 0 ||
14191                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14192                 {
14193                         /* starting a new token type, so start a new command */
14194                         if (i > 0)
14195                                 appendPQExpBufferStr(q, ";\n");
14196                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14197                                                           fmtQualifiedDumpable(cfginfo));
14198                         /* tokenname needs quoting, dictname does NOT */
14199                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14200                                                           fmtId(tokenname), dictname);
14201                 }
14202                 else
14203                         appendPQExpBuffer(q, ", %s", dictname);
14204         }
14205
14206         if (ntups > 0)
14207                 appendPQExpBufferStr(q, ";\n");
14208
14209         PQclear(res);
14210
14211         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14212                                           fmtQualifiedDumpable(cfginfo));
14213
14214         if (dopt->binary_upgrade)
14215                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14216                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14217                                                                                 cfginfo->dobj.namespace->dobj.name);
14218
14219         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14220                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14221                                          cfginfo->dobj.name,
14222                                          cfginfo->dobj.namespace->dobj.name,
14223                                          NULL,
14224                                          cfginfo->rolname,
14225                                          false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14226                                          q->data, delq->data, NULL,
14227                                          NULL, 0,
14228                                          NULL, NULL);
14229
14230         /* Dump Configuration Comments */
14231         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14232                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14233                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14234                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14235
14236         destroyPQExpBuffer(q);
14237         destroyPQExpBuffer(delq);
14238         destroyPQExpBuffer(query);
14239         free(qcfgname);
14240 }
14241
14242 /*
14243  * dumpForeignDataWrapper
14244  *        write out a single foreign-data wrapper definition
14245  */
14246 static void
14247 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14248 {
14249         DumpOptions *dopt = fout->dopt;
14250         PQExpBuffer q;
14251         PQExpBuffer delq;
14252         char       *qfdwname;
14253
14254         /* Skip if not to be dumped */
14255         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14256                 return;
14257
14258         q = createPQExpBuffer();
14259         delq = createPQExpBuffer();
14260
14261         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14262
14263         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14264                                           qfdwname);
14265
14266         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14267                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14268
14269         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14270                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14271
14272         if (strlen(fdwinfo->fdwoptions) > 0)
14273                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14274
14275         appendPQExpBufferStr(q, ";\n");
14276
14277         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14278                                           qfdwname);
14279
14280         if (dopt->binary_upgrade)
14281                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14282                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14283                                                                                 NULL);
14284
14285         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14286                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14287                                          fdwinfo->dobj.name,
14288                                          NULL,
14289                                          NULL,
14290                                          fdwinfo->rolname,
14291                                          false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14292                                          q->data, delq->data, NULL,
14293                                          NULL, 0,
14294                                          NULL, NULL);
14295
14296         /* Dump Foreign Data Wrapper Comments */
14297         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14298                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14299                                         NULL, fdwinfo->rolname,
14300                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14301
14302         /* Handle the ACL */
14303         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14304                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14305                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14306                                 NULL, fdwinfo->rolname,
14307                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14308                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14309
14310         free(qfdwname);
14311
14312         destroyPQExpBuffer(q);
14313         destroyPQExpBuffer(delq);
14314 }
14315
14316 /*
14317  * dumpForeignServer
14318  *        write out a foreign server definition
14319  */
14320 static void
14321 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14322 {
14323         DumpOptions *dopt = fout->dopt;
14324         PQExpBuffer q;
14325         PQExpBuffer delq;
14326         PQExpBuffer query;
14327         PGresult   *res;
14328         char       *qsrvname;
14329         char       *fdwname;
14330
14331         /* Skip if not to be dumped */
14332         if (!srvinfo->dobj.dump || dopt->dataOnly)
14333                 return;
14334
14335         q = createPQExpBuffer();
14336         delq = createPQExpBuffer();
14337         query = createPQExpBuffer();
14338
14339         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14340
14341         /* look up the foreign-data wrapper */
14342         appendPQExpBuffer(query, "SELECT fdwname "
14343                                           "FROM pg_foreign_data_wrapper w "
14344                                           "WHERE w.oid = '%u'",
14345                                           srvinfo->srvfdw);
14346         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14347         fdwname = PQgetvalue(res, 0, 0);
14348
14349         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14350         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14351         {
14352                 appendPQExpBufferStr(q, " TYPE ");
14353                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14354         }
14355         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14356         {
14357                 appendPQExpBufferStr(q, " VERSION ");
14358                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14359         }
14360
14361         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14362         appendPQExpBufferStr(q, fmtId(fdwname));
14363
14364         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14365                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14366
14367         appendPQExpBufferStr(q, ";\n");
14368
14369         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14370                                           qsrvname);
14371
14372         if (dopt->binary_upgrade)
14373                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14374                                                                                 "SERVER", qsrvname, NULL);
14375
14376         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14377                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14378                                          srvinfo->dobj.name,
14379                                          NULL,
14380                                          NULL,
14381                                          srvinfo->rolname,
14382                                          false, "SERVER", SECTION_PRE_DATA,
14383                                          q->data, delq->data, NULL,
14384                                          NULL, 0,
14385                                          NULL, NULL);
14386
14387         /* Dump Foreign Server Comments */
14388         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14389                 dumpComment(fout, "SERVER", qsrvname,
14390                                         NULL, srvinfo->rolname,
14391                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14392
14393         /* Handle the ACL */
14394         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14395                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14396                                 "FOREIGN SERVER", qsrvname, NULL,
14397                                 NULL, srvinfo->rolname,
14398                                 srvinfo->srvacl, srvinfo->rsrvacl,
14399                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14400
14401         /* Dump user mappings */
14402         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14403                 dumpUserMappings(fout,
14404                                                  srvinfo->dobj.name, NULL,
14405                                                  srvinfo->rolname,
14406                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14407
14408         free(qsrvname);
14409
14410         destroyPQExpBuffer(q);
14411         destroyPQExpBuffer(delq);
14412         destroyPQExpBuffer(query);
14413 }
14414
14415 /*
14416  * dumpUserMappings
14417  *
14418  * This routine is used to dump any user mappings associated with the
14419  * server handed to this routine. Should be called after ArchiveEntry()
14420  * for the server.
14421  */
14422 static void
14423 dumpUserMappings(Archive *fout,
14424                                  const char *servername, const char *namespace,
14425                                  const char *owner,
14426                                  CatalogId catalogId, DumpId dumpId)
14427 {
14428         PQExpBuffer q;
14429         PQExpBuffer delq;
14430         PQExpBuffer query;
14431         PQExpBuffer tag;
14432         PGresult   *res;
14433         int                     ntups;
14434         int                     i_usename;
14435         int                     i_umoptions;
14436         int                     i;
14437
14438         q = createPQExpBuffer();
14439         tag = createPQExpBuffer();
14440         delq = createPQExpBuffer();
14441         query = createPQExpBuffer();
14442
14443         /*
14444          * We read from the publicly accessible view pg_user_mappings, so as not
14445          * to fail if run by a non-superuser.  Note that the view will show
14446          * umoptions as null if the user hasn't got privileges for the associated
14447          * server; this means that pg_dump will dump such a mapping, but with no
14448          * OPTIONS clause.  A possible alternative is to skip such mappings
14449          * altogether, but it's not clear that that's an improvement.
14450          */
14451         appendPQExpBuffer(query,
14452                                           "SELECT usename, "
14453                                           "array_to_string(ARRAY("
14454                                           "SELECT quote_ident(option_name) || ' ' || "
14455                                           "quote_literal(option_value) "
14456                                           "FROM pg_options_to_table(umoptions) "
14457                                           "ORDER BY option_name"
14458                                           "), E',\n    ') AS umoptions "
14459                                           "FROM pg_user_mappings "
14460                                           "WHERE srvid = '%u' "
14461                                           "ORDER BY usename",
14462                                           catalogId.oid);
14463
14464         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14465
14466         ntups = PQntuples(res);
14467         i_usename = PQfnumber(res, "usename");
14468         i_umoptions = PQfnumber(res, "umoptions");
14469
14470         for (i = 0; i < ntups; i++)
14471         {
14472                 char       *usename;
14473                 char       *umoptions;
14474
14475                 usename = PQgetvalue(res, i, i_usename);
14476                 umoptions = PQgetvalue(res, i, i_umoptions);
14477
14478                 resetPQExpBuffer(q);
14479                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14480                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14481
14482                 if (umoptions && strlen(umoptions) > 0)
14483                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14484
14485                 appendPQExpBufferStr(q, ";\n");
14486
14487                 resetPQExpBuffer(delq);
14488                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14489                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14490
14491                 resetPQExpBuffer(tag);
14492                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14493                                                   usename, servername);
14494
14495                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14496                                          tag->data,
14497                                          namespace,
14498                                          NULL,
14499                                          owner, false,
14500                                          "USER MAPPING", SECTION_PRE_DATA,
14501                                          q->data, delq->data, NULL,
14502                                          &dumpId, 1,
14503                                          NULL, NULL);
14504         }
14505
14506         PQclear(res);
14507
14508         destroyPQExpBuffer(query);
14509         destroyPQExpBuffer(delq);
14510         destroyPQExpBuffer(tag);
14511         destroyPQExpBuffer(q);
14512 }
14513
14514 /*
14515  * Write out default privileges information
14516  */
14517 static void
14518 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14519 {
14520         DumpOptions *dopt = fout->dopt;
14521         PQExpBuffer q;
14522         PQExpBuffer tag;
14523         const char *type;
14524
14525         /* Skip if not to be dumped */
14526         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14527                 return;
14528
14529         q = createPQExpBuffer();
14530         tag = createPQExpBuffer();
14531
14532         switch (daclinfo->defaclobjtype)
14533         {
14534                 case DEFACLOBJ_RELATION:
14535                         type = "TABLES";
14536                         break;
14537                 case DEFACLOBJ_SEQUENCE:
14538                         type = "SEQUENCES";
14539                         break;
14540                 case DEFACLOBJ_FUNCTION:
14541                         type = "FUNCTIONS";
14542                         break;
14543                 case DEFACLOBJ_TYPE:
14544                         type = "TYPES";
14545                         break;
14546                 case DEFACLOBJ_NAMESPACE:
14547                         type = "SCHEMAS";
14548                         break;
14549                 default:
14550                         /* shouldn't get here */
14551                         exit_horribly(NULL,
14552                                                   "unrecognized object type in default privileges: %d\n",
14553                                                   (int) daclinfo->defaclobjtype);
14554                         type = "";                      /* keep compiler quiet */
14555         }
14556
14557         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14558
14559         /* build the actual command(s) for this tuple */
14560         if (!buildDefaultACLCommands(type,
14561                                                                  daclinfo->dobj.namespace != NULL ?
14562                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14563                                                                  daclinfo->defaclacl,
14564                                                                  daclinfo->rdefaclacl,
14565                                                                  daclinfo->initdefaclacl,
14566                                                                  daclinfo->initrdefaclacl,
14567                                                                  daclinfo->defaclrole,
14568                                                                  fout->remoteVersion,
14569                                                                  q))
14570                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14571                                           daclinfo->defaclacl);
14572
14573         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14574                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14575                                          tag->data,
14576                                          daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14577                                          NULL,
14578                                          daclinfo->defaclrole,
14579                                          false, "DEFAULT ACL", SECTION_POST_DATA,
14580                                          q->data, "", NULL,
14581                                          NULL, 0,
14582                                          NULL, NULL);
14583
14584         destroyPQExpBuffer(tag);
14585         destroyPQExpBuffer(q);
14586 }
14587
14588 /*----------
14589  * Write out grant/revoke information
14590  *
14591  * 'objCatId' is the catalog ID of the underlying object.
14592  * 'objDumpId' is the dump ID of the underlying object.
14593  * 'type' must be one of
14594  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14595  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14596  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14597  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14598  *              (Currently we assume that subname is only provided for table columns.)
14599  * 'nspname' is the namespace the object is in (NULL if none).
14600  * 'owner' is the owner, NULL if there is no owner (for languages).
14601  * 'acls' contains the ACL string of the object from the appropriate system
14602  *              catalog field; it will be passed to buildACLCommands for building the
14603  *              appropriate GRANT commands.
14604  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14605  *              object; it will be passed to buildACLCommands for building the
14606  *              appropriate REVOKE commands.
14607  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14608  *              privileges, to be recorded into pg_init_privs
14609  * 'initracls' In binary-upgrade mode, ACL string of the object's
14610  *              revoked-from-default privileges, to be recorded into pg_init_privs
14611  *
14612  * NB: initacls/initracls are needed because extensions can set privileges on
14613  * an object during the extension's script file and we record those into
14614  * pg_init_privs as that object's initial privileges.
14615  *----------
14616  */
14617 static void
14618 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14619                 const char *type, const char *name, const char *subname,
14620                 const char *nspname, const char *owner,
14621                 const char *acls, const char *racls,
14622                 const char *initacls, const char *initracls)
14623 {
14624         DumpOptions *dopt = fout->dopt;
14625         PQExpBuffer sql;
14626
14627         /* Do nothing if ACL dump is not enabled */
14628         if (dopt->aclsSkip)
14629                 return;
14630
14631         /* --data-only skips ACLs *except* BLOB ACLs */
14632         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14633                 return;
14634
14635         sql = createPQExpBuffer();
14636
14637         /*
14638          * Check to see if this object has had any initial ACLs included for it.
14639          * If so, we are in binary upgrade mode and these are the ACLs to turn
14640          * into GRANT and REVOKE statements to set and record the initial
14641          * privileges for an extension object.  Let the backend know that these
14642          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14643          * before and after.
14644          */
14645         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14646         {
14647                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14648                 if (!buildACLCommands(name, subname, nspname, type,
14649                                                           initacls, initracls, owner,
14650                                                           "", fout->remoteVersion, sql))
14651                         exit_horribly(NULL,
14652                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14653                                                   initacls, initracls, name, type);
14654                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14655         }
14656
14657         if (!buildACLCommands(name, subname, nspname, type,
14658                                                   acls, racls, owner,
14659                                                   "", fout->remoteVersion, sql))
14660                 exit_horribly(NULL,
14661                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14662                                           acls, racls, name, type);
14663
14664         if (sql->len > 0)
14665         {
14666                 PQExpBuffer tag = createPQExpBuffer();
14667
14668                 if (subname)
14669                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14670                 else
14671                         appendPQExpBuffer(tag, "%s %s", type, name);
14672
14673                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14674                                          tag->data, nspname,
14675                                          NULL,
14676                                          owner ? owner : "",
14677                                          false, "ACL", SECTION_NONE,
14678                                          sql->data, "", NULL,
14679                                          &(objDumpId), 1,
14680                                          NULL, NULL);
14681                 destroyPQExpBuffer(tag);
14682         }
14683
14684         destroyPQExpBuffer(sql);
14685 }
14686
14687 /*
14688  * dumpSecLabel
14689  *
14690  * This routine is used to dump any security labels associated with the
14691  * object handed to this routine. The routine takes the object type
14692  * and object name (ready to print, except for schema decoration), plus
14693  * the namespace and owner of the object (for labeling the ArchiveEntry),
14694  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14695  * plus the dump ID for the object (for setting a dependency).
14696  * If a matching pg_seclabel entry is found, it is dumped.
14697  *
14698  * Note: although this routine takes a dumpId for dependency purposes,
14699  * that purpose is just to mark the dependency in the emitted dump file
14700  * for possible future use by pg_restore.  We do NOT use it for determining
14701  * ordering of the label in the dump file, because this routine is called
14702  * after dependency sorting occurs.  This routine should be called just after
14703  * calling ArchiveEntry() for the specified object.
14704  */
14705 static void
14706 dumpSecLabel(Archive *fout, const char *type, const char *name,
14707                          const char *namespace, const char *owner,
14708                          CatalogId catalogId, int subid, DumpId dumpId)
14709 {
14710         DumpOptions *dopt = fout->dopt;
14711         SecLabelItem *labels;
14712         int                     nlabels;
14713         int                     i;
14714         PQExpBuffer query;
14715
14716         /* do nothing, if --no-security-labels is supplied */
14717         if (dopt->no_security_labels)
14718                 return;
14719
14720         /* Security labels are schema not data ... except blob labels are data */
14721         if (strcmp(type, "LARGE OBJECT") != 0)
14722         {
14723                 if (dopt->dataOnly)
14724                         return;
14725         }
14726         else
14727         {
14728                 /* We do dump blob security labels in binary-upgrade mode */
14729                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14730                         return;
14731         }
14732
14733         /* Search for security labels associated with catalogId, using table */
14734         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14735
14736         query = createPQExpBuffer();
14737
14738         for (i = 0; i < nlabels; i++)
14739         {
14740                 /*
14741                  * Ignore label entries for which the subid doesn't match.
14742                  */
14743                 if (labels[i].objsubid != subid)
14744                         continue;
14745
14746                 appendPQExpBuffer(query,
14747                                                   "SECURITY LABEL FOR %s ON %s ",
14748                                                   fmtId(labels[i].provider), type);
14749                 if (namespace && *namespace)
14750                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14751                 appendPQExpBuffer(query, "%s IS ", name);
14752                 appendStringLiteralAH(query, labels[i].label, fout);
14753                 appendPQExpBufferStr(query, ";\n");
14754         }
14755
14756         if (query->len > 0)
14757         {
14758                 PQExpBuffer tag = createPQExpBuffer();
14759
14760                 appendPQExpBuffer(tag, "%s %s", type, name);
14761                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14762                                          tag->data, namespace, NULL, owner,
14763                                          false, "SECURITY LABEL", SECTION_NONE,
14764                                          query->data, "", NULL,
14765                                          &(dumpId), 1,
14766                                          NULL, NULL);
14767                 destroyPQExpBuffer(tag);
14768         }
14769
14770         destroyPQExpBuffer(query);
14771 }
14772
14773 /*
14774  * dumpTableSecLabel
14775  *
14776  * As above, but dump security label for both the specified table (or view)
14777  * and its columns.
14778  */
14779 static void
14780 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14781 {
14782         DumpOptions *dopt = fout->dopt;
14783         SecLabelItem *labels;
14784         int                     nlabels;
14785         int                     i;
14786         PQExpBuffer query;
14787         PQExpBuffer target;
14788
14789         /* do nothing, if --no-security-labels is supplied */
14790         if (dopt->no_security_labels)
14791                 return;
14792
14793         /* SecLabel are SCHEMA not data */
14794         if (dopt->dataOnly)
14795                 return;
14796
14797         /* Search for comments associated with relation, using table */
14798         nlabels = findSecLabels(fout,
14799                                                         tbinfo->dobj.catId.tableoid,
14800                                                         tbinfo->dobj.catId.oid,
14801                                                         &labels);
14802
14803         /* If security labels exist, build SECURITY LABEL statements */
14804         if (nlabels <= 0)
14805                 return;
14806
14807         query = createPQExpBuffer();
14808         target = createPQExpBuffer();
14809
14810         for (i = 0; i < nlabels; i++)
14811         {
14812                 const char *colname;
14813                 const char *provider = labels[i].provider;
14814                 const char *label = labels[i].label;
14815                 int                     objsubid = labels[i].objsubid;
14816
14817                 resetPQExpBuffer(target);
14818                 if (objsubid == 0)
14819                 {
14820                         appendPQExpBuffer(target, "%s %s", reltypename,
14821                                                           fmtQualifiedDumpable(tbinfo));
14822                 }
14823                 else
14824                 {
14825                         colname = getAttrName(objsubid, tbinfo);
14826                         /* first fmtXXX result must be consumed before calling again */
14827                         appendPQExpBuffer(target, "COLUMN %s",
14828                                                           fmtQualifiedDumpable(tbinfo));
14829                         appendPQExpBuffer(target, ".%s", fmtId(colname));
14830                 }
14831                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14832                                                   fmtId(provider), target->data);
14833                 appendStringLiteralAH(query, label, fout);
14834                 appendPQExpBufferStr(query, ";\n");
14835         }
14836         if (query->len > 0)
14837         {
14838                 resetPQExpBuffer(target);
14839                 appendPQExpBuffer(target, "%s %s", reltypename,
14840                                                   fmtId(tbinfo->dobj.name));
14841                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14842                                          target->data,
14843                                          tbinfo->dobj.namespace->dobj.name,
14844                                          NULL, tbinfo->rolname,
14845                                          false, "SECURITY LABEL", SECTION_NONE,
14846                                          query->data, "", NULL,
14847                                          &(tbinfo->dobj.dumpId), 1,
14848                                          NULL, NULL);
14849         }
14850         destroyPQExpBuffer(query);
14851         destroyPQExpBuffer(target);
14852 }
14853
14854 /*
14855  * findSecLabels
14856  *
14857  * Find the security label(s), if any, associated with the given object.
14858  * All the objsubid values associated with the given classoid/objoid are
14859  * found with one search.
14860  */
14861 static int
14862 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14863 {
14864         /* static storage for table of security labels */
14865         static SecLabelItem *labels = NULL;
14866         static int      nlabels = -1;
14867
14868         SecLabelItem *middle = NULL;
14869         SecLabelItem *low;
14870         SecLabelItem *high;
14871         int                     nmatch;
14872
14873         /* Get security labels if we didn't already */
14874         if (nlabels < 0)
14875                 nlabels = collectSecLabels(fout, &labels);
14876
14877         if (nlabels <= 0)                       /* no labels, so no match is possible */
14878         {
14879                 *items = NULL;
14880                 return 0;
14881         }
14882
14883         /*
14884          * Do binary search to find some item matching the object.
14885          */
14886         low = &labels[0];
14887         high = &labels[nlabels - 1];
14888         while (low <= high)
14889         {
14890                 middle = low + (high - low) / 2;
14891
14892                 if (classoid < middle->classoid)
14893                         high = middle - 1;
14894                 else if (classoid > middle->classoid)
14895                         low = middle + 1;
14896                 else if (objoid < middle->objoid)
14897                         high = middle - 1;
14898                 else if (objoid > middle->objoid)
14899                         low = middle + 1;
14900                 else
14901                         break;                          /* found a match */
14902         }
14903
14904         if (low > high)                         /* no matches */
14905         {
14906                 *items = NULL;
14907                 return 0;
14908         }
14909
14910         /*
14911          * Now determine how many items match the object.  The search loop
14912          * invariant still holds: only items between low and high inclusive could
14913          * match.
14914          */
14915         nmatch = 1;
14916         while (middle > low)
14917         {
14918                 if (classoid != middle[-1].classoid ||
14919                         objoid != middle[-1].objoid)
14920                         break;
14921                 middle--;
14922                 nmatch++;
14923         }
14924
14925         *items = middle;
14926
14927         middle += nmatch;
14928         while (middle <= high)
14929         {
14930                 if (classoid != middle->classoid ||
14931                         objoid != middle->objoid)
14932                         break;
14933                 middle++;
14934                 nmatch++;
14935         }
14936
14937         return nmatch;
14938 }
14939
14940 /*
14941  * collectSecLabels
14942  *
14943  * Construct a table of all security labels available for database objects.
14944  * It's much faster to pull them all at once.
14945  *
14946  * The table is sorted by classoid/objid/objsubid for speed in lookup.
14947  */
14948 static int
14949 collectSecLabels(Archive *fout, SecLabelItem **items)
14950 {
14951         PGresult   *res;
14952         PQExpBuffer query;
14953         int                     i_label;
14954         int                     i_provider;
14955         int                     i_classoid;
14956         int                     i_objoid;
14957         int                     i_objsubid;
14958         int                     ntups;
14959         int                     i;
14960         SecLabelItem *labels;
14961
14962         query = createPQExpBuffer();
14963
14964         appendPQExpBufferStr(query,
14965                                                  "SELECT label, provider, classoid, objoid, objsubid "
14966                                                  "FROM pg_catalog.pg_seclabel "
14967                                                  "ORDER BY classoid, objoid, objsubid");
14968
14969         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14970
14971         /* Construct lookup table containing OIDs in numeric form */
14972         i_label = PQfnumber(res, "label");
14973         i_provider = PQfnumber(res, "provider");
14974         i_classoid = PQfnumber(res, "classoid");
14975         i_objoid = PQfnumber(res, "objoid");
14976         i_objsubid = PQfnumber(res, "objsubid");
14977
14978         ntups = PQntuples(res);
14979
14980         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
14981
14982         for (i = 0; i < ntups; i++)
14983         {
14984                 labels[i].label = PQgetvalue(res, i, i_label);
14985                 labels[i].provider = PQgetvalue(res, i, i_provider);
14986                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
14987                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
14988                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
14989         }
14990
14991         /* Do NOT free the PGresult since we are keeping pointers into it */
14992         destroyPQExpBuffer(query);
14993
14994         *items = labels;
14995         return ntups;
14996 }
14997
14998 /*
14999  * dumpTable
15000  *        write out to fout the declarations (not data) of a user-defined table
15001  */
15002 static void
15003 dumpTable(Archive *fout, TableInfo *tbinfo)
15004 {
15005         DumpOptions *dopt = fout->dopt;
15006         char       *namecopy;
15007
15008         /*
15009          * noop if we are not dumping anything about this table, or if we are
15010          * doing a data-only dump
15011          */
15012         if (!tbinfo->dobj.dump || dopt->dataOnly)
15013                 return;
15014
15015         if (tbinfo->relkind == RELKIND_SEQUENCE)
15016                 dumpSequence(fout, tbinfo);
15017         else
15018                 dumpTableSchema(fout, tbinfo);
15019
15020         /* Handle the ACL here */
15021         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15022         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15023         {
15024                 const char *objtype =
15025                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15026
15027                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15028                                 objtype, namecopy, NULL,
15029                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15030                                 tbinfo->relacl, tbinfo->rrelacl,
15031                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15032         }
15033
15034         /*
15035          * Handle column ACLs, if any.  Note: we pull these with a separate query
15036          * rather than trying to fetch them during getTableAttrs, so that we won't
15037          * miss ACLs on system columns.
15038          */
15039         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15040         {
15041                 PQExpBuffer query = createPQExpBuffer();
15042                 PGresult   *res;
15043                 int                     i;
15044
15045                 if (fout->remoteVersion >= 90600)
15046                 {
15047                         PQExpBuffer acl_subquery = createPQExpBuffer();
15048                         PQExpBuffer racl_subquery = createPQExpBuffer();
15049                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15050                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15051
15052                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15053                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15054                                                         dopt->binary_upgrade);
15055
15056                         appendPQExpBuffer(query,
15057                                                           "SELECT at.attname, "
15058                                                           "%s AS attacl, "
15059                                                           "%s AS rattacl, "
15060                                                           "%s AS initattacl, "
15061                                                           "%s AS initrattacl "
15062                                                           "FROM pg_catalog.pg_attribute at "
15063                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15064                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15065                                                           "(at.attrelid = pip.objoid "
15066                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15067                                                           "AND at.attnum = pip.objsubid) "
15068                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15069                                                           "NOT at.attisdropped "
15070                                                           "AND ("
15071                                                           "%s IS NOT NULL OR "
15072                                                           "%s IS NOT NULL OR "
15073                                                           "%s IS NOT NULL OR "
15074                                                           "%s IS NOT NULL)"
15075                                                           "ORDER BY at.attnum",
15076                                                           acl_subquery->data,
15077                                                           racl_subquery->data,
15078                                                           initacl_subquery->data,
15079                                                           initracl_subquery->data,
15080                                                           tbinfo->dobj.catId.oid,
15081                                                           acl_subquery->data,
15082                                                           racl_subquery->data,
15083                                                           initacl_subquery->data,
15084                                                           initracl_subquery->data);
15085
15086                         destroyPQExpBuffer(acl_subquery);
15087                         destroyPQExpBuffer(racl_subquery);
15088                         destroyPQExpBuffer(initacl_subquery);
15089                         destroyPQExpBuffer(initracl_subquery);
15090                 }
15091                 else
15092                 {
15093                         appendPQExpBuffer(query,
15094                                                           "SELECT attname, attacl, NULL as rattacl, "
15095                                                           "NULL AS initattacl, NULL AS initrattacl "
15096                                                           "FROM pg_catalog.pg_attribute "
15097                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15098                                                           "AND attacl IS NOT NULL "
15099                                                           "ORDER BY attnum",
15100                                                           tbinfo->dobj.catId.oid);
15101                 }
15102
15103                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15104
15105                 for (i = 0; i < PQntuples(res); i++)
15106                 {
15107                         char       *attname = PQgetvalue(res, i, 0);
15108                         char       *attacl = PQgetvalue(res, i, 1);
15109                         char       *rattacl = PQgetvalue(res, i, 2);
15110                         char       *initattacl = PQgetvalue(res, i, 3);
15111                         char       *initrattacl = PQgetvalue(res, i, 4);
15112                         char       *attnamecopy;
15113
15114                         attnamecopy = pg_strdup(fmtId(attname));
15115                         /* Column's GRANT type is always TABLE */
15116                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15117                                         "TABLE", namecopy, attnamecopy,
15118                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15119                                         attacl, rattacl, initattacl, initrattacl);
15120                         free(attnamecopy);
15121                 }
15122                 PQclear(res);
15123                 destroyPQExpBuffer(query);
15124         }
15125
15126         free(namecopy);
15127
15128         return;
15129 }
15130
15131 /*
15132  * Create the AS clause for a view or materialized view. The semicolon is
15133  * stripped because a materialized view must add a WITH NO DATA clause.
15134  *
15135  * This returns a new buffer which must be freed by the caller.
15136  */
15137 static PQExpBuffer
15138 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15139 {
15140         PQExpBuffer query = createPQExpBuffer();
15141         PQExpBuffer result = createPQExpBuffer();
15142         PGresult   *res;
15143         int                     len;
15144
15145         /* Fetch the view definition */
15146         appendPQExpBuffer(query,
15147                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15148                                           tbinfo->dobj.catId.oid);
15149
15150         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15151
15152         if (PQntuples(res) != 1)
15153         {
15154                 if (PQntuples(res) < 1)
15155                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15156                                                   tbinfo->dobj.name);
15157                 else
15158                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15159                                                   tbinfo->dobj.name);
15160         }
15161
15162         len = PQgetlength(res, 0, 0);
15163
15164         if (len == 0)
15165                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15166                                           tbinfo->dobj.name);
15167
15168         /* Strip off the trailing semicolon so that other things may follow. */
15169         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15170         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15171
15172         PQclear(res);
15173         destroyPQExpBuffer(query);
15174
15175         return result;
15176 }
15177
15178 /*
15179  * Create a dummy AS clause for a view.  This is used when the real view
15180  * definition has to be postponed because of circular dependencies.
15181  * We must duplicate the view's external properties -- column names and types
15182  * (including collation) -- so that it works for subsequent references.
15183  *
15184  * This returns a new buffer which must be freed by the caller.
15185  */
15186 static PQExpBuffer
15187 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15188 {
15189         PQExpBuffer result = createPQExpBuffer();
15190         int                     j;
15191
15192         appendPQExpBufferStr(result, "SELECT");
15193
15194         for (j = 0; j < tbinfo->numatts; j++)
15195         {
15196                 if (j > 0)
15197                         appendPQExpBufferChar(result, ',');
15198                 appendPQExpBufferStr(result, "\n    ");
15199
15200                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15201
15202                 /*
15203                  * Must add collation if not default for the type, because CREATE OR
15204                  * REPLACE VIEW won't change it
15205                  */
15206                 if (OidIsValid(tbinfo->attcollation[j]))
15207                 {
15208                         CollInfo   *coll;
15209
15210                         coll = findCollationByOid(tbinfo->attcollation[j]);
15211                         if (coll)
15212                                 appendPQExpBuffer(result, " COLLATE %s",
15213                                                                   fmtQualifiedDumpable(coll));
15214                 }
15215
15216                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15217         }
15218
15219         return result;
15220 }
15221
15222 /*
15223  * dumpTableSchema
15224  *        write the declaration (not data) of one user-defined table or view
15225  */
15226 static void
15227 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15228 {
15229         DumpOptions *dopt = fout->dopt;
15230         PQExpBuffer q = createPQExpBuffer();
15231         PQExpBuffer delq = createPQExpBuffer();
15232         char       *qrelname;
15233         char       *qualrelname;
15234         int                     numParents;
15235         TableInfo **parents;
15236         int                     actual_atts;    /* number of attrs in this CREATE statement */
15237         const char *reltypename;
15238         char       *storage;
15239         char       *srvname;
15240         char       *ftoptions;
15241         int                     j,
15242                                 k;
15243
15244         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15245         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15246
15247         if (dopt->binary_upgrade)
15248                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15249                                                                                                 tbinfo->dobj.catId.oid);
15250
15251         /* Is it a table or a view? */
15252         if (tbinfo->relkind == RELKIND_VIEW)
15253         {
15254                 PQExpBuffer result;
15255
15256                 /*
15257                  * Note: keep this code in sync with the is_view case in dumpRule()
15258                  */
15259
15260                 reltypename = "VIEW";
15261
15262                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15263
15264                 if (dopt->binary_upgrade)
15265                         binary_upgrade_set_pg_class_oids(fout, q,
15266                                                                                          tbinfo->dobj.catId.oid, false);
15267
15268                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15269
15270                 if (tbinfo->dummy_view)
15271                         result = createDummyViewAsClause(fout, tbinfo);
15272                 else
15273                 {
15274                         if (nonemptyReloptions(tbinfo->reloptions))
15275                         {
15276                                 appendPQExpBufferStr(q, " WITH (");
15277                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15278                                 appendPQExpBufferChar(q, ')');
15279                         }
15280                         result = createViewAsClause(fout, tbinfo);
15281                 }
15282                 appendPQExpBuffer(q, " AS\n%s", result->data);
15283                 destroyPQExpBuffer(result);
15284
15285                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15286                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15287                 appendPQExpBufferStr(q, ";\n");
15288         }
15289         else
15290         {
15291                 switch (tbinfo->relkind)
15292                 {
15293                         case RELKIND_FOREIGN_TABLE:
15294                                 {
15295                                         PQExpBuffer query = createPQExpBuffer();
15296                                         PGresult   *res;
15297                                         int                     i_srvname;
15298                                         int                     i_ftoptions;
15299
15300                                         reltypename = "FOREIGN TABLE";
15301
15302                                         /* retrieve name of foreign server and generic options */
15303                                         appendPQExpBuffer(query,
15304                                                                           "SELECT fs.srvname, "
15305                                                                           "pg_catalog.array_to_string(ARRAY("
15306                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15307                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15308                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15309                                                                           "ORDER BY option_name"
15310                                                                           "), E',\n    ') AS ftoptions "
15311                                                                           "FROM pg_catalog.pg_foreign_table ft "
15312                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15313                                                                           "ON (fs.oid = ft.ftserver) "
15314                                                                           "WHERE ft.ftrelid = '%u'",
15315                                                                           tbinfo->dobj.catId.oid);
15316                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15317                                         i_srvname = PQfnumber(res, "srvname");
15318                                         i_ftoptions = PQfnumber(res, "ftoptions");
15319                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15320                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15321                                         PQclear(res);
15322                                         destroyPQExpBuffer(query);
15323                                         break;
15324                                 }
15325                         case RELKIND_MATVIEW:
15326                                 reltypename = "MATERIALIZED VIEW";
15327                                 srvname = NULL;
15328                                 ftoptions = NULL;
15329                                 break;
15330                         default:
15331                                 reltypename = "TABLE";
15332                                 srvname = NULL;
15333                                 ftoptions = NULL;
15334                 }
15335
15336                 numParents = tbinfo->numParents;
15337                 parents = tbinfo->parents;
15338
15339                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15340
15341                 if (dopt->binary_upgrade)
15342                         binary_upgrade_set_pg_class_oids(fout, q,
15343                                                                                          tbinfo->dobj.catId.oid, false);
15344
15345                 appendPQExpBuffer(q, "CREATE %s%s %s",
15346                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15347                                                   "UNLOGGED " : "",
15348                                                   reltypename,
15349                                                   qualrelname);
15350
15351                 /*
15352                  * Attach to type, if reloftype; except in case of a binary upgrade,
15353                  * we dump the table normally and attach it to the type afterward.
15354                  */
15355                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15356                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15357
15358                 /*
15359                  * If the table is a partition, dump it as such; except in the case of
15360                  * a binary upgrade, we dump the table normally and attach it to the
15361                  * parent afterward.
15362                  */
15363                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15364                 {
15365                         TableInfo  *parentRel = tbinfo->parents[0];
15366
15367                         /*
15368                          * With partitions, unlike inheritance, there can only be one
15369                          * parent.
15370                          */
15371                         if (tbinfo->numParents != 1)
15372                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15373                                                           tbinfo->numParents, tbinfo->dobj.name);
15374
15375                         appendPQExpBuffer(q, " PARTITION OF %s",
15376                                                           fmtQualifiedDumpable(parentRel));
15377                 }
15378
15379                 if (tbinfo->relkind != RELKIND_MATVIEW)
15380                 {
15381                         /* Dump the attributes */
15382                         actual_atts = 0;
15383                         for (j = 0; j < tbinfo->numatts; j++)
15384                         {
15385                                 /*
15386                                  * Normally, dump if it's locally defined in this table, and
15387                                  * not dropped.  But for binary upgrade, we'll dump all the
15388                                  * columns, and then fix up the dropped and nonlocal cases
15389                                  * below.
15390                                  */
15391                                 if (shouldPrintColumn(dopt, tbinfo, j))
15392                                 {
15393                                         /*
15394                                          * Default value --- suppress if to be printed separately.
15395                                          */
15396                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15397                                                                                            !tbinfo->attrdefs[j]->separate);
15398
15399                                         /*
15400                                          * Not Null constraint --- suppress if inherited, except
15401                                          * in binary-upgrade case where that won't work.
15402                                          */
15403                                         bool            has_notnull = (tbinfo->notnull[j] &&
15404                                                                                            (!tbinfo->inhNotNull[j] ||
15405                                                                                                 dopt->binary_upgrade));
15406
15407                                         /*
15408                                          * Skip column if fully defined by reloftype or the
15409                                          * partition parent.
15410                                          */
15411                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15412                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15413                                                 continue;
15414
15415                                         /* Format properly if not first attr */
15416                                         if (actual_atts == 0)
15417                                                 appendPQExpBufferStr(q, " (");
15418                                         else
15419                                                 appendPQExpBufferChar(q, ',');
15420                                         appendPQExpBufferStr(q, "\n    ");
15421                                         actual_atts++;
15422
15423                                         /* Attribute name */
15424                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15425
15426                                         if (tbinfo->attisdropped[j])
15427                                         {
15428                                                 /*
15429                                                  * ALTER TABLE DROP COLUMN clears
15430                                                  * pg_attribute.atttypid, so we will not have gotten a
15431                                                  * valid type name; insert INTEGER as a stopgap. We'll
15432                                                  * clean things up later.
15433                                                  */
15434                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15435                                                 /* Skip all the rest, too */
15436                                                 continue;
15437                                         }
15438
15439                                         /*
15440                                          * Attribute type
15441                                          *
15442                                          * In binary-upgrade mode, we always include the type. If
15443                                          * we aren't in binary-upgrade mode, then we skip the type
15444                                          * when creating a typed table ('OF type_name') or a
15445                                          * partition ('PARTITION OF'), since the type comes from
15446                                          * the parent/partitioned table.
15447                                          */
15448                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15449                                         {
15450                                                 appendPQExpBuffer(q, " %s",
15451                                                                                   tbinfo->atttypnames[j]);
15452                                         }
15453
15454                                         /* Add collation if not default for the type */
15455                                         if (OidIsValid(tbinfo->attcollation[j]))
15456                                         {
15457                                                 CollInfo   *coll;
15458
15459                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15460                                                 if (coll)
15461                                                         appendPQExpBuffer(q, " COLLATE %s",
15462                                                                                           fmtQualifiedDumpable(coll));
15463                                         }
15464
15465                                         if (has_default)
15466                                                 appendPQExpBuffer(q, " DEFAULT %s",
15467                                                                                   tbinfo->attrdefs[j]->adef_expr);
15468
15469                                         if (has_notnull)
15470                                                 appendPQExpBufferStr(q, " NOT NULL");
15471                                 }
15472                         }
15473
15474                         /*
15475                          * Add non-inherited CHECK constraints, if any.
15476                          */
15477                         for (j = 0; j < tbinfo->ncheck; j++)
15478                         {
15479                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15480
15481                                 if (constr->separate || !constr->conislocal)
15482                                         continue;
15483
15484                                 if (actual_atts == 0)
15485                                         appendPQExpBufferStr(q, " (\n    ");
15486                                 else
15487                                         appendPQExpBufferStr(q, ",\n    ");
15488
15489                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15490                                                                   fmtId(constr->dobj.name));
15491                                 appendPQExpBufferStr(q, constr->condef);
15492
15493                                 actual_atts++;
15494                         }
15495
15496                         if (actual_atts)
15497                                 appendPQExpBufferStr(q, "\n)");
15498                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15499                                            !dopt->binary_upgrade))
15500                         {
15501                                 /*
15502                                  * We must have a parenthesized attribute list, even though
15503                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15504                                  */
15505                                 appendPQExpBufferStr(q, " (\n)");
15506                         }
15507
15508                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15509                         {
15510                                 appendPQExpBufferChar(q, '\n');
15511                                 appendPQExpBufferStr(q, tbinfo->partbound);
15512                         }
15513
15514                         /* Emit the INHERITS clause, except if this is a partition. */
15515                         if (numParents > 0 &&
15516                                 !tbinfo->ispartition &&
15517                                 !dopt->binary_upgrade)
15518                         {
15519                                 appendPQExpBufferStr(q, "\nINHERITS (");
15520                                 for (k = 0; k < numParents; k++)
15521                                 {
15522                                         TableInfo  *parentRel = parents[k];
15523
15524                                         if (k > 0)
15525                                                 appendPQExpBufferStr(q, ", ");
15526                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15527                                 }
15528                                 appendPQExpBufferChar(q, ')');
15529                         }
15530
15531                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15532                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15533
15534                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15535                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15536                 }
15537
15538                 if (nonemptyReloptions(tbinfo->reloptions) ||
15539                         nonemptyReloptions(tbinfo->toast_reloptions))
15540                 {
15541                         bool            addcomma = false;
15542
15543                         appendPQExpBufferStr(q, "\nWITH (");
15544                         if (nonemptyReloptions(tbinfo->reloptions))
15545                         {
15546                                 addcomma = true;
15547                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15548                         }
15549                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15550                         {
15551                                 if (addcomma)
15552                                         appendPQExpBufferStr(q, ", ");
15553                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15554                                                                                 fout);
15555                         }
15556                         appendPQExpBufferChar(q, ')');
15557                 }
15558
15559                 /* Dump generic options if any */
15560                 if (ftoptions && ftoptions[0])
15561                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15562
15563                 /*
15564                  * For materialized views, create the AS clause just like a view. At
15565                  * this point, we always mark the view as not populated.
15566                  */
15567                 if (tbinfo->relkind == RELKIND_MATVIEW)
15568                 {
15569                         PQExpBuffer result;
15570
15571                         result = createViewAsClause(fout, tbinfo);
15572                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15573                                                           result->data);
15574                         destroyPQExpBuffer(result);
15575                 }
15576                 else
15577                         appendPQExpBufferStr(q, ";\n");
15578
15579                 /*
15580                  * To create binary-compatible heap files, we have to ensure the same
15581                  * physical column order, including dropped columns, as in the
15582                  * original.  Therefore, we create dropped columns above and drop them
15583                  * here, also updating their attlen/attalign values so that the
15584                  * dropped column can be skipped properly.  (We do not bother with
15585                  * restoring the original attbyval setting.)  Also, inheritance
15586                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15587                  * using an INHERITS clause --- the latter would possibly mess up the
15588                  * column order.  That also means we have to take care about setting
15589                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15590                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15591                  *
15592                  * We process foreign and partitioned tables here, even though they
15593                  * lack heap storage, because they can participate in inheritance
15594                  * relationships and we want this stuff to be consistent across the
15595                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15596                  * and matviews, even though they have storage, because we don't
15597                  * support altering or dropping columns in them, nor can they be part
15598                  * of inheritance trees.
15599                  */
15600                 if (dopt->binary_upgrade &&
15601                         (tbinfo->relkind == RELKIND_RELATION ||
15602                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15603                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15604                 {
15605                         for (j = 0; j < tbinfo->numatts; j++)
15606                         {
15607                                 if (tbinfo->attisdropped[j])
15608                                 {
15609                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15610                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15611                                                                           "SET attlen = %d, "
15612                                                                           "attalign = '%c', attbyval = false\n"
15613                                                                           "WHERE attname = ",
15614                                                                           tbinfo->attlen[j],
15615                                                                           tbinfo->attalign[j]);
15616                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15617                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15618                                         appendStringLiteralAH(q, qualrelname, fout);
15619                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15620
15621                                         if (tbinfo->relkind == RELKIND_RELATION ||
15622                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15623                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15624                                                                                   qualrelname);
15625                                         else
15626                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15627                                                                                   qualrelname);
15628                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15629                                                                           fmtId(tbinfo->attnames[j]));
15630                                 }
15631                                 else if (!tbinfo->attislocal[j])
15632                                 {
15633                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15634                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15635                                                                                  "SET attislocal = false\n"
15636                                                                                  "WHERE attname = ");
15637                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15638                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15639                                         appendStringLiteralAH(q, qualrelname, fout);
15640                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15641                                 }
15642                         }
15643
15644                         for (k = 0; k < tbinfo->ncheck; k++)
15645                         {
15646                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15647
15648                                 if (constr->separate || constr->conislocal)
15649                                         continue;
15650
15651                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15652                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15653                                                                   qualrelname);
15654                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15655                                                                   fmtId(constr->dobj.name));
15656                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15657                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15658                                                                          "SET conislocal = false\n"
15659                                                                          "WHERE contype = 'c' AND conname = ");
15660                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15661                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15662                                 appendStringLiteralAH(q, qualrelname, fout);
15663                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15664                         }
15665
15666                         if (numParents > 0)
15667                         {
15668                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15669                                 for (k = 0; k < numParents; k++)
15670                                 {
15671                                         TableInfo  *parentRel = parents[k];
15672
15673                                         /* In the partitioning case, we alter the parent */
15674                                         if (tbinfo->ispartition)
15675                                                 appendPQExpBuffer(q,
15676                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15677                                                                                   fmtQualifiedDumpable(parentRel));
15678                                         else
15679                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15680                                                                                   qualrelname);
15681
15682                                         /* Partition needs specifying the bounds */
15683                                         if (tbinfo->ispartition)
15684                                                 appendPQExpBuffer(q, "%s %s;\n",
15685                                                                                   qualrelname,
15686                                                                                   tbinfo->partbound);
15687                                         else
15688                                                 appendPQExpBuffer(q, "%s;\n",
15689                                                                                   fmtQualifiedDumpable(parentRel));
15690                                 }
15691                         }
15692
15693                         if (tbinfo->reloftype)
15694                         {
15695                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15696                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15697                                                                   qualrelname,
15698                                                                   tbinfo->reloftype);
15699                         }
15700                 }
15701
15702                 /*
15703                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15704                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15705                  * TOAST tables semi-independently, here we see them only as children
15706                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15707                  * child toast table is handled below.)
15708                  */
15709                 if (dopt->binary_upgrade &&
15710                         (tbinfo->relkind == RELKIND_RELATION ||
15711                          tbinfo->relkind == RELKIND_MATVIEW))
15712                 {
15713                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15714                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15715                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15716                                                           "WHERE oid = ",
15717                                                           tbinfo->frozenxid, tbinfo->minmxid);
15718                         appendStringLiteralAH(q, qualrelname, fout);
15719                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15720
15721                         if (tbinfo->toast_oid)
15722                         {
15723                                 /*
15724                                  * The toast table will have the same OID at restore, so we
15725                                  * can safely target it by OID.
15726                                  */
15727                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15728                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15729                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15730                                                                   "WHERE oid = '%u';\n",
15731                                                                   tbinfo->toast_frozenxid,
15732                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15733                         }
15734                 }
15735
15736                 /*
15737                  * In binary_upgrade mode, restore matviews' populated status by
15738                  * poking pg_class directly.  This is pretty ugly, but we can't use
15739                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15740                  * matview is not populated even though this matview is; in any case,
15741                  * we want to transfer the matview's heap storage, not run REFRESH.
15742                  */
15743                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15744                         tbinfo->relispopulated)
15745                 {
15746                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15747                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15748                                                                  "SET relispopulated = 't'\n"
15749                                                                  "WHERE oid = ");
15750                         appendStringLiteralAH(q, qualrelname, fout);
15751                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15752                 }
15753
15754                 /*
15755                  * Dump additional per-column properties that we can't handle in the
15756                  * main CREATE TABLE command.
15757                  */
15758                 for (j = 0; j < tbinfo->numatts; j++)
15759                 {
15760                         /* None of this applies to dropped columns */
15761                         if (tbinfo->attisdropped[j])
15762                                 continue;
15763
15764                         /*
15765                          * If we didn't dump the column definition explicitly above, and
15766                          * it is NOT NULL and did not inherit that property from a parent,
15767                          * we have to mark it separately.
15768                          */
15769                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
15770                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15771                         {
15772                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15773                                                                   qualrelname);
15774                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15775                                                                   fmtId(tbinfo->attnames[j]));
15776                         }
15777
15778                         /*
15779                          * Dump per-column statistics information. We only issue an ALTER
15780                          * TABLE statement if the attstattarget entry for this column is
15781                          * non-negative (i.e. it's not the default value)
15782                          */
15783                         if (tbinfo->attstattarget[j] >= 0)
15784                         {
15785                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15786                                                                   qualrelname);
15787                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15788                                                                   fmtId(tbinfo->attnames[j]));
15789                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15790                                                                   tbinfo->attstattarget[j]);
15791                         }
15792
15793                         /*
15794                          * Dump per-column storage information.  The statement is only
15795                          * dumped if the storage has been changed from the type's default.
15796                          */
15797                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15798                         {
15799                                 switch (tbinfo->attstorage[j])
15800                                 {
15801                                         case 'p':
15802                                                 storage = "PLAIN";
15803                                                 break;
15804                                         case 'e':
15805                                                 storage = "EXTERNAL";
15806                                                 break;
15807                                         case 'm':
15808                                                 storage = "MAIN";
15809                                                 break;
15810                                         case 'x':
15811                                                 storage = "EXTENDED";
15812                                                 break;
15813                                         default:
15814                                                 storage = NULL;
15815                                 }
15816
15817                                 /*
15818                                  * Only dump the statement if it's a storage type we recognize
15819                                  */
15820                                 if (storage != NULL)
15821                                 {
15822                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15823                                                                           qualrelname);
15824                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
15825                                                                           fmtId(tbinfo->attnames[j]));
15826                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
15827                                                                           storage);
15828                                 }
15829                         }
15830
15831                         /*
15832                          * Dump per-column attributes.
15833                          */
15834                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
15835                         {
15836                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15837                                                                   qualrelname);
15838                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15839                                                                   fmtId(tbinfo->attnames[j]));
15840                                 appendPQExpBuffer(q, "SET (%s);\n",
15841                                                                   tbinfo->attoptions[j]);
15842                         }
15843
15844                         /*
15845                          * Dump per-column fdw options.
15846                          */
15847                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15848                                 tbinfo->attfdwoptions[j] &&
15849                                 tbinfo->attfdwoptions[j][0] != '\0')
15850                         {
15851                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
15852                                                                   qualrelname);
15853                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15854                                                                   fmtId(tbinfo->attnames[j]));
15855                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
15856                                                                   tbinfo->attfdwoptions[j]);
15857                         }
15858                 }
15859         }
15860
15861         /*
15862          * dump properties we only have ALTER TABLE syntax for
15863          */
15864         if ((tbinfo->relkind == RELKIND_RELATION ||
15865                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
15866                  tbinfo->relkind == RELKIND_MATVIEW) &&
15867                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
15868         {
15869                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
15870                 {
15871                         /* nothing to do, will be set when the index is dumped */
15872                 }
15873                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
15874                 {
15875                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
15876                                                           qualrelname);
15877                 }
15878                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
15879                 {
15880                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
15881                                                           qualrelname);
15882                 }
15883         }
15884
15885         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE && tbinfo->hasoids)
15886                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s SET WITH OIDS;\n",
15887                                                   qualrelname);
15888
15889         if (tbinfo->forcerowsec)
15890                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
15891                                                   qualrelname);
15892
15893         if (dopt->binary_upgrade)
15894                 binary_upgrade_extension_member(q, &tbinfo->dobj,
15895                                                                                 reltypename, qrelname,
15896                                                                                 tbinfo->dobj.namespace->dobj.name);
15897
15898         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15899                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15900                                          tbinfo->dobj.name,
15901                                          tbinfo->dobj.namespace->dobj.name,
15902                                          (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
15903                                          tbinfo->rolname,
15904                                          (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
15905                                          reltypename,
15906                                          tbinfo->postponed_def ?
15907                                          SECTION_POST_DATA : SECTION_PRE_DATA,
15908                                          q->data, delq->data, NULL,
15909                                          NULL, 0,
15910                                          NULL, NULL);
15911
15912
15913         /* Dump Table Comments */
15914         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15915                 dumpTableComment(fout, tbinfo, reltypename);
15916
15917         /* Dump Table Security Labels */
15918         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
15919                 dumpTableSecLabel(fout, tbinfo, reltypename);
15920
15921         /* Dump comments on inlined table constraints */
15922         for (j = 0; j < tbinfo->ncheck; j++)
15923         {
15924                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15925
15926                 if (constr->separate || !constr->conislocal)
15927                         continue;
15928
15929                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15930                         dumpTableConstraintComment(fout, constr);
15931         }
15932
15933         destroyPQExpBuffer(q);
15934         destroyPQExpBuffer(delq);
15935         free(qrelname);
15936         free(qualrelname);
15937 }
15938
15939 /*
15940  * dumpAttrDef --- dump an attribute's default-value declaration
15941  */
15942 static void
15943 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
15944 {
15945         DumpOptions *dopt = fout->dopt;
15946         TableInfo  *tbinfo = adinfo->adtable;
15947         int                     adnum = adinfo->adnum;
15948         PQExpBuffer q;
15949         PQExpBuffer delq;
15950         char       *qualrelname;
15951         char       *tag;
15952
15953         /* Skip if table definition not to be dumped */
15954         if (!tbinfo->dobj.dump || dopt->dataOnly)
15955                 return;
15956
15957         /* Skip if not "separate"; it was dumped in the table's definition */
15958         if (!adinfo->separate)
15959                 return;
15960
15961         q = createPQExpBuffer();
15962         delq = createPQExpBuffer();
15963
15964         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15965
15966         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15967                                           qualrelname);
15968         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
15969                                           fmtId(tbinfo->attnames[adnum - 1]),
15970                                           adinfo->adef_expr);
15971
15972         appendPQExpBuffer(delq, "ALTER TABLE %s ",
15973                                           qualrelname);
15974         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
15975                                           fmtId(tbinfo->attnames[adnum - 1]));
15976
15977         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
15978
15979         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15980                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
15981                                          tag,
15982                                          tbinfo->dobj.namespace->dobj.name,
15983                                          NULL,
15984                                          tbinfo->rolname,
15985                                          false, "DEFAULT", SECTION_PRE_DATA,
15986                                          q->data, delq->data, NULL,
15987                                          NULL, 0,
15988                                          NULL, NULL);
15989
15990         free(tag);
15991         destroyPQExpBuffer(q);
15992         destroyPQExpBuffer(delq);
15993         free(qualrelname);
15994 }
15995
15996 /*
15997  * getAttrName: extract the correct name for an attribute
15998  *
15999  * The array tblInfo->attnames[] only provides names of user attributes;
16000  * if a system attribute number is supplied, we have to fake it.
16001  * We also do a little bit of bounds checking for safety's sake.
16002  */
16003 static const char *
16004 getAttrName(int attrnum, TableInfo *tblInfo)
16005 {
16006         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16007                 return tblInfo->attnames[attrnum - 1];
16008         switch (attrnum)
16009         {
16010                 case SelfItemPointerAttributeNumber:
16011                         return "ctid";
16012                 case ObjectIdAttributeNumber:
16013                         return "oid";
16014                 case MinTransactionIdAttributeNumber:
16015                         return "xmin";
16016                 case MinCommandIdAttributeNumber:
16017                         return "cmin";
16018                 case MaxTransactionIdAttributeNumber:
16019                         return "xmax";
16020                 case MaxCommandIdAttributeNumber:
16021                         return "cmax";
16022                 case TableOidAttributeNumber:
16023                         return "tableoid";
16024         }
16025         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16026                                   attrnum, tblInfo->dobj.name);
16027         return NULL;                            /* keep compiler quiet */
16028 }
16029
16030 /*
16031  * dumpIndex
16032  *        write out to fout a user-defined index
16033  */
16034 static void
16035 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16036 {
16037         DumpOptions *dopt = fout->dopt;
16038         TableInfo  *tbinfo = indxinfo->indextable;
16039         bool            is_constraint = (indxinfo->indexconstraint != 0);
16040         PQExpBuffer q;
16041         PQExpBuffer delq;
16042         char       *qindxname;
16043
16044         if (dopt->dataOnly)
16045                 return;
16046
16047         q = createPQExpBuffer();
16048         delq = createPQExpBuffer();
16049
16050         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16051
16052         /*
16053          * If there's an associated constraint, don't dump the index per se, but
16054          * do dump any comment for it.  (This is safe because dependency ordering
16055          * will have ensured the constraint is emitted first.)  Note that the
16056          * emitted comment has to be shown as depending on the constraint, not the
16057          * index, in such cases.
16058          */
16059         if (!is_constraint)
16060         {
16061                 if (dopt->binary_upgrade)
16062                         binary_upgrade_set_pg_class_oids(fout, q,
16063                                                                                          indxinfo->dobj.catId.oid, true);
16064
16065                 /* Plain secondary index */
16066                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16067
16068                 /* If the index is clustered, we need to record that. */
16069                 if (indxinfo->indisclustered)
16070                 {
16071                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16072                                                           fmtQualifiedDumpable(tbinfo));
16073                         /* index name is not qualified in this syntax */
16074                         appendPQExpBuffer(q, " ON %s;\n",
16075                                                           qindxname);
16076                 }
16077
16078                 /* If the index defines identity, we need to record that. */
16079                 if (indxinfo->indisreplident)
16080                 {
16081                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16082                                                           fmtQualifiedDumpable(tbinfo));
16083                         /* index name is not qualified in this syntax */
16084                         appendPQExpBuffer(q, " INDEX %s;\n",
16085                                                           qindxname);
16086                 }
16087
16088                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16089                                                   fmtQualifiedDumpable(indxinfo));
16090
16091                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16092                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16093                                                  indxinfo->dobj.name,
16094                                                  tbinfo->dobj.namespace->dobj.name,
16095                                                  indxinfo->tablespace,
16096                                                  tbinfo->rolname, false,
16097                                                  "INDEX", SECTION_POST_DATA,
16098                                                  q->data, delq->data, NULL,
16099                                                  NULL, 0,
16100                                                  NULL, NULL);
16101         }
16102
16103         /* Dump Index Comments */
16104         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16105                 dumpComment(fout, "INDEX", qindxname,
16106                                         tbinfo->dobj.namespace->dobj.name,
16107                                         tbinfo->rolname,
16108                                         indxinfo->dobj.catId, 0,
16109                                         is_constraint ? indxinfo->indexconstraint :
16110                                         indxinfo->dobj.dumpId);
16111
16112         destroyPQExpBuffer(q);
16113         destroyPQExpBuffer(delq);
16114         free(qindxname);
16115 }
16116
16117 /*
16118  * dumpIndexAttach
16119  *        write out to fout a partitioned-index attachment clause
16120  */
16121 static void
16122 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16123 {
16124         if (fout->dopt->dataOnly)
16125                 return;
16126
16127         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16128         {
16129                 PQExpBuffer q = createPQExpBuffer();
16130
16131                 appendPQExpBuffer(q, "\nALTER INDEX %s ",
16132                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16133                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16134                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16135
16136                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16137                                          attachinfo->dobj.name,
16138                                          NULL, NULL,
16139                                          "",
16140                                          false, "INDEX ATTACH", SECTION_POST_DATA,
16141                                          q->data, "", NULL,
16142                                          NULL, 0,
16143                                          NULL, NULL);
16144
16145                 destroyPQExpBuffer(q);
16146         }
16147 }
16148
16149 /*
16150  * dumpStatisticsExt
16151  *        write out to fout an extended statistics object
16152  */
16153 static void
16154 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16155 {
16156         DumpOptions *dopt = fout->dopt;
16157         PQExpBuffer q;
16158         PQExpBuffer delq;
16159         PQExpBuffer query;
16160         char       *qstatsextname;
16161         PGresult   *res;
16162         char       *stxdef;
16163
16164         /* Skip if not to be dumped */
16165         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16166                 return;
16167
16168         q = createPQExpBuffer();
16169         delq = createPQExpBuffer();
16170         query = createPQExpBuffer();
16171
16172         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16173
16174         appendPQExpBuffer(query, "SELECT "
16175                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16176                                           statsextinfo->dobj.catId.oid);
16177
16178         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16179
16180         stxdef = PQgetvalue(res, 0, 0);
16181
16182         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16183         appendPQExpBuffer(q, "%s;\n", stxdef);
16184
16185         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16186                                           fmtQualifiedDumpable(statsextinfo));
16187
16188         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16189                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16190                                          statsextinfo->dobj.dumpId,
16191                                          statsextinfo->dobj.name,
16192                                          statsextinfo->dobj.namespace->dobj.name,
16193                                          NULL,
16194                                          statsextinfo->rolname, false,
16195                                          "STATISTICS", SECTION_POST_DATA,
16196                                          q->data, delq->data, NULL,
16197                                          NULL, 0,
16198                                          NULL, NULL);
16199
16200         /* Dump Statistics Comments */
16201         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16202                 dumpComment(fout, "STATISTICS", qstatsextname,
16203                                         statsextinfo->dobj.namespace->dobj.name,
16204                                         statsextinfo->rolname,
16205                                         statsextinfo->dobj.catId, 0,
16206                                         statsextinfo->dobj.dumpId);
16207
16208         PQclear(res);
16209         destroyPQExpBuffer(q);
16210         destroyPQExpBuffer(delq);
16211         destroyPQExpBuffer(query);
16212         free(qstatsextname);
16213 }
16214
16215 /*
16216  * dumpConstraint
16217  *        write out to fout a user-defined constraint
16218  */
16219 static void
16220 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16221 {
16222         DumpOptions *dopt = fout->dopt;
16223         TableInfo  *tbinfo = coninfo->contable;
16224         PQExpBuffer q;
16225         PQExpBuffer delq;
16226         char       *tag = NULL;
16227
16228         /* Skip if not to be dumped */
16229         if (!coninfo->dobj.dump || dopt->dataOnly)
16230                 return;
16231
16232         q = createPQExpBuffer();
16233         delq = createPQExpBuffer();
16234
16235         if (coninfo->contype == 'p' ||
16236                 coninfo->contype == 'u' ||
16237                 coninfo->contype == 'x')
16238         {
16239                 /* Index-related constraint */
16240                 IndxInfo   *indxinfo;
16241                 int                     k;
16242
16243                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16244
16245                 if (indxinfo == NULL)
16246                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16247                                                   coninfo->dobj.name);
16248
16249                 if (dopt->binary_upgrade)
16250                         binary_upgrade_set_pg_class_oids(fout, q,
16251                                                                                          indxinfo->dobj.catId.oid, true);
16252
16253                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16254                                                   fmtQualifiedDumpable(tbinfo));
16255                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16256                                                   fmtId(coninfo->dobj.name));
16257
16258                 if (coninfo->condef)
16259                 {
16260                         /* pg_get_constraintdef should have provided everything */
16261                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16262                 }
16263                 else
16264                 {
16265                         appendPQExpBuffer(q, "%s (",
16266                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16267                         for (k = 0; k < indxinfo->indnkeys; k++)
16268                         {
16269                                 int                     indkey = (int) indxinfo->indkeys[k];
16270                                 const char *attname;
16271
16272                                 if (indkey == InvalidAttrNumber)
16273                                         break;
16274                                 attname = getAttrName(indkey, tbinfo);
16275
16276                                 appendPQExpBuffer(q, "%s%s",
16277                                                                   (k == 0) ? "" : ", ",
16278                                                                   fmtId(attname));
16279                         }
16280
16281                         appendPQExpBufferChar(q, ')');
16282
16283                         if (nonemptyReloptions(indxinfo->indreloptions))
16284                         {
16285                                 appendPQExpBufferStr(q, " WITH (");
16286                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16287                                 appendPQExpBufferChar(q, ')');
16288                         }
16289
16290                         if (coninfo->condeferrable)
16291                         {
16292                                 appendPQExpBufferStr(q, " DEFERRABLE");
16293                                 if (coninfo->condeferred)
16294                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16295                         }
16296
16297                         appendPQExpBufferStr(q, ";\n");
16298                 }
16299
16300                 /* If the index is clustered, we need to record that. */
16301                 if (indxinfo->indisclustered)
16302                 {
16303                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16304                                                           fmtQualifiedDumpable(tbinfo));
16305                         /* index name is not qualified in this syntax */
16306                         appendPQExpBuffer(q, " ON %s;\n",
16307                                                           fmtId(indxinfo->dobj.name));
16308                 }
16309
16310                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16311                                                   fmtQualifiedDumpable(tbinfo));
16312                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16313                                                   fmtId(coninfo->dobj.name));
16314
16315                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16316
16317                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16318                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16319                                                  tag,
16320                                                  tbinfo->dobj.namespace->dobj.name,
16321                                                  indxinfo->tablespace,
16322                                                  tbinfo->rolname, false,
16323                                                  "CONSTRAINT", SECTION_POST_DATA,
16324                                                  q->data, delq->data, NULL,
16325                                                  NULL, 0,
16326                                                  NULL, NULL);
16327         }
16328         else if (coninfo->contype == 'f')
16329         {
16330                 /*
16331                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16332                  * current table data is not processed
16333                  */
16334                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16335                                                   fmtQualifiedDumpable(tbinfo));
16336                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16337                                                   fmtId(coninfo->dobj.name),
16338                                                   coninfo->condef);
16339
16340                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16341                                                   fmtQualifiedDumpable(tbinfo));
16342                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16343                                                   fmtId(coninfo->dobj.name));
16344
16345                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16346
16347                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16348                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16349                                                  tag,
16350                                                  tbinfo->dobj.namespace->dobj.name,
16351                                                  NULL,
16352                                                  tbinfo->rolname, false,
16353                                                  "FK CONSTRAINT", SECTION_POST_DATA,
16354                                                  q->data, delq->data, NULL,
16355                                                  NULL, 0,
16356                                                  NULL, NULL);
16357         }
16358         else if (coninfo->contype == 'c' && tbinfo)
16359         {
16360                 /* CHECK constraint on a table */
16361
16362                 /* Ignore if not to be dumped separately, or if it was inherited */
16363                 if (coninfo->separate && coninfo->conislocal)
16364                 {
16365                         /* not ONLY since we want it to propagate to children */
16366                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16367                                                           fmtQualifiedDumpable(tbinfo));
16368                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16369                                                           fmtId(coninfo->dobj.name),
16370                                                           coninfo->condef);
16371
16372                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16373                                                           fmtQualifiedDumpable(tbinfo));
16374                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16375                                                           fmtId(coninfo->dobj.name));
16376
16377                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16378
16379                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16380                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16381                                                          tag,
16382                                                          tbinfo->dobj.namespace->dobj.name,
16383                                                          NULL,
16384                                                          tbinfo->rolname, false,
16385                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16386                                                          q->data, delq->data, NULL,
16387                                                          NULL, 0,
16388                                                          NULL, NULL);
16389                 }
16390         }
16391         else if (coninfo->contype == 'c' && tbinfo == NULL)
16392         {
16393                 /* CHECK constraint on a domain */
16394                 TypeInfo   *tyinfo = coninfo->condomain;
16395
16396                 /* Ignore if not to be dumped separately */
16397                 if (coninfo->separate)
16398                 {
16399                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16400                                                           fmtQualifiedDumpable(tyinfo));
16401                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16402                                                           fmtId(coninfo->dobj.name),
16403                                                           coninfo->condef);
16404
16405                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16406                                                           fmtQualifiedDumpable(tyinfo));
16407                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16408                                                           fmtId(coninfo->dobj.name));
16409
16410                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16411
16412                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16413                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16414                                                          tag,
16415                                                          tyinfo->dobj.namespace->dobj.name,
16416                                                          NULL,
16417                                                          tyinfo->rolname, false,
16418                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16419                                                          q->data, delq->data, NULL,
16420                                                          NULL, 0,
16421                                                          NULL, NULL);
16422                 }
16423         }
16424         else
16425         {
16426                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16427                                           coninfo->contype);
16428         }
16429
16430         /* Dump Constraint Comments --- only works for table constraints */
16431         if (tbinfo && coninfo->separate &&
16432                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16433                 dumpTableConstraintComment(fout, coninfo);
16434
16435         free(tag);
16436         destroyPQExpBuffer(q);
16437         destroyPQExpBuffer(delq);
16438 }
16439
16440 /*
16441  * dumpTableConstraintComment --- dump a constraint's comment if any
16442  *
16443  * This is split out because we need the function in two different places
16444  * depending on whether the constraint is dumped as part of CREATE TABLE
16445  * or as a separate ALTER command.
16446  */
16447 static void
16448 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16449 {
16450         TableInfo  *tbinfo = coninfo->contable;
16451         PQExpBuffer conprefix = createPQExpBuffer();
16452         char       *qtabname;
16453
16454         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16455
16456         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16457                                           fmtId(coninfo->dobj.name));
16458
16459         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16460                 dumpComment(fout, conprefix->data, qtabname,
16461                                         tbinfo->dobj.namespace->dobj.name,
16462                                         tbinfo->rolname,
16463                                         coninfo->dobj.catId, 0,
16464                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16465
16466         destroyPQExpBuffer(conprefix);
16467         free(qtabname);
16468 }
16469
16470 /*
16471  * findLastBuiltinOid_V71 -
16472  *
16473  * find the last built in oid
16474  *
16475  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16476  * pg_database entry for the current database.
16477  */
16478 static Oid
16479 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
16480 {
16481         PGresult   *res;
16482         Oid                     last_oid;
16483         PQExpBuffer query = createPQExpBuffer();
16484
16485         resetPQExpBuffer(query);
16486         appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
16487         appendStringLiteralAH(query, dbname, fout);
16488
16489         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16490         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16491         PQclear(res);
16492         destroyPQExpBuffer(query);
16493
16494         return last_oid;
16495 }
16496
16497 /*
16498  * dumpSequence
16499  *        write the declaration (not data) of one user-defined sequence
16500  */
16501 static void
16502 dumpSequence(Archive *fout, TableInfo *tbinfo)
16503 {
16504         DumpOptions *dopt = fout->dopt;
16505         PGresult   *res;
16506         char       *startv,
16507                            *incby,
16508                            *maxv,
16509                            *minv,
16510                            *cache,
16511                            *seqtype;
16512         bool            cycled;
16513         bool            is_ascending;
16514         int64           default_minv,
16515                                 default_maxv;
16516         char            bufm[32],
16517                                 bufx[32];
16518         PQExpBuffer query = createPQExpBuffer();
16519         PQExpBuffer delqry = createPQExpBuffer();
16520         char       *qseqname;
16521
16522         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16523
16524         if (fout->remoteVersion >= 100000)
16525         {
16526                 appendPQExpBuffer(query,
16527                                                   "SELECT format_type(seqtypid, NULL), "
16528                                                   "seqstart, seqincrement, "
16529                                                   "seqmax, seqmin, "
16530                                                   "seqcache, seqcycle "
16531                                                   "FROM pg_catalog.pg_sequence "
16532                                                   "WHERE seqrelid = '%u'::oid",
16533                                                   tbinfo->dobj.catId.oid);
16534         }
16535         else if (fout->remoteVersion >= 80400)
16536         {
16537                 /*
16538                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16539                  *
16540                  * Note: it might seem that 'bigint' potentially needs to be
16541                  * schema-qualified, but actually that's a keyword.
16542                  */
16543                 appendPQExpBuffer(query,
16544                                                   "SELECT 'bigint' AS sequence_type, "
16545                                                   "start_value, increment_by, max_value, min_value, "
16546                                                   "cache_value, is_cycled FROM %s",
16547                                                   fmtQualifiedDumpable(tbinfo));
16548         }
16549         else
16550         {
16551                 appendPQExpBuffer(query,
16552                                                   "SELECT 'bigint' AS sequence_type, "
16553                                                   "0 AS start_value, increment_by, max_value, min_value, "
16554                                                   "cache_value, is_cycled FROM %s",
16555                                                   fmtQualifiedDumpable(tbinfo));
16556         }
16557
16558         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16559
16560         if (PQntuples(res) != 1)
16561         {
16562                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16563                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16564                                                                  PQntuples(res)),
16565                                   tbinfo->dobj.name, PQntuples(res));
16566                 exit_nicely(1);
16567         }
16568
16569         seqtype = PQgetvalue(res, 0, 0);
16570         startv = PQgetvalue(res, 0, 1);
16571         incby = PQgetvalue(res, 0, 2);
16572         maxv = PQgetvalue(res, 0, 3);
16573         minv = PQgetvalue(res, 0, 4);
16574         cache = PQgetvalue(res, 0, 5);
16575         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16576
16577         /* Calculate default limits for a sequence of this type */
16578         is_ascending = (incby[0] != '-');
16579         if (strcmp(seqtype, "smallint") == 0)
16580         {
16581                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16582                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16583         }
16584         else if (strcmp(seqtype, "integer") == 0)
16585         {
16586                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16587                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16588         }
16589         else if (strcmp(seqtype, "bigint") == 0)
16590         {
16591                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16592                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16593         }
16594         else
16595         {
16596                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16597                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16598         }
16599
16600         /*
16601          * 64-bit strtol() isn't very portable, so convert the limits to strings
16602          * and compare that way.
16603          */
16604         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16605         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16606
16607         /* Don't print minv/maxv if they match the respective default limit */
16608         if (strcmp(minv, bufm) == 0)
16609                 minv = NULL;
16610         if (strcmp(maxv, bufx) == 0)
16611                 maxv = NULL;
16612
16613         /*
16614          * Identity sequences are not to be dropped separately.
16615          */
16616         if (!tbinfo->is_identity_sequence)
16617         {
16618                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16619                                                   fmtQualifiedDumpable(tbinfo));
16620         }
16621
16622         resetPQExpBuffer(query);
16623
16624         if (dopt->binary_upgrade)
16625         {
16626                 binary_upgrade_set_pg_class_oids(fout, query,
16627                                                                                  tbinfo->dobj.catId.oid, false);
16628                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16629                                                                                                 tbinfo->dobj.catId.oid);
16630         }
16631
16632         if (tbinfo->is_identity_sequence)
16633         {
16634                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16635
16636                 appendPQExpBuffer(query,
16637                                                   "ALTER TABLE %s ",
16638                                                   fmtQualifiedDumpable(owning_tab));
16639                 appendPQExpBuffer(query,
16640                                                   "ALTER COLUMN %s ADD GENERATED ",
16641                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16642                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16643                         appendPQExpBuffer(query, "ALWAYS");
16644                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16645                         appendPQExpBuffer(query, "BY DEFAULT");
16646                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16647                                                   fmtQualifiedDumpable(tbinfo));
16648         }
16649         else
16650         {
16651                 appendPQExpBuffer(query,
16652                                                   "CREATE SEQUENCE %s\n",
16653                                                   fmtQualifiedDumpable(tbinfo));
16654
16655                 if (strcmp(seqtype, "bigint") != 0)
16656                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16657         }
16658
16659         if (fout->remoteVersion >= 80400)
16660                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16661
16662         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16663
16664         if (minv)
16665                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16666         else
16667                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16668
16669         if (maxv)
16670                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16671         else
16672                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16673
16674         appendPQExpBuffer(query,
16675                                           "    CACHE %s%s",
16676                                           cache, (cycled ? "\n    CYCLE" : ""));
16677
16678         if (tbinfo->is_identity_sequence)
16679                 appendPQExpBufferStr(query, "\n);\n");
16680         else
16681                 appendPQExpBufferStr(query, ";\n");
16682
16683         /* binary_upgrade:      no need to clear TOAST table oid */
16684
16685         if (dopt->binary_upgrade)
16686                 binary_upgrade_extension_member(query, &tbinfo->dobj,
16687                                                                                 "SEQUENCE", qseqname,
16688                                                                                 tbinfo->dobj.namespace->dobj.name);
16689
16690         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16691                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16692                                          tbinfo->dobj.name,
16693                                          tbinfo->dobj.namespace->dobj.name,
16694                                          NULL,
16695                                          tbinfo->rolname,
16696                                          false, "SEQUENCE", SECTION_PRE_DATA,
16697                                          query->data, delqry->data, NULL,
16698                                          NULL, 0,
16699                                          NULL, NULL);
16700
16701         /*
16702          * If the sequence is owned by a table column, emit the ALTER for it as a
16703          * separate TOC entry immediately following the sequence's own entry. It's
16704          * OK to do this rather than using full sorting logic, because the
16705          * dependency that tells us it's owned will have forced the table to be
16706          * created first.  We can't just include the ALTER in the TOC entry
16707          * because it will fail if we haven't reassigned the sequence owner to
16708          * match the table's owner.
16709          *
16710          * We need not schema-qualify the table reference because both sequence
16711          * and table must be in the same schema.
16712          */
16713         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
16714         {
16715                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16716
16717                 if (owning_tab == NULL)
16718                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
16719                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16720
16721                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16722                 {
16723                         resetPQExpBuffer(query);
16724                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16725                                                           fmtQualifiedDumpable(tbinfo));
16726                         appendPQExpBuffer(query, " OWNED BY %s",
16727                                                           fmtQualifiedDumpable(owning_tab));
16728                         appendPQExpBuffer(query, ".%s;\n",
16729                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16730
16731                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16732                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16733                                                          tbinfo->dobj.name,
16734                                                          tbinfo->dobj.namespace->dobj.name,
16735                                                          NULL,
16736                                                          tbinfo->rolname,
16737                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
16738                                                          query->data, "", NULL,
16739                                                          &(tbinfo->dobj.dumpId), 1,
16740                                                          NULL, NULL);
16741                 }
16742         }
16743
16744         /* Dump Sequence Comments and Security Labels */
16745         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16746                 dumpComment(fout, "SEQUENCE", qseqname,
16747                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16748                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16749
16750         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16751                 dumpSecLabel(fout, "SEQUENCE", qseqname,
16752                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16753                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16754
16755         PQclear(res);
16756
16757         destroyPQExpBuffer(query);
16758         destroyPQExpBuffer(delqry);
16759         free(qseqname);
16760 }
16761
16762 /*
16763  * dumpSequenceData
16764  *        write the data of one user-defined sequence
16765  */
16766 static void
16767 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16768 {
16769         TableInfo  *tbinfo = tdinfo->tdtable;
16770         PGresult   *res;
16771         char       *last;
16772         bool            called;
16773         PQExpBuffer query = createPQExpBuffer();
16774
16775         appendPQExpBuffer(query,
16776                                           "SELECT last_value, is_called FROM %s",
16777                                           fmtQualifiedDumpable(tbinfo));
16778
16779         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16780
16781         if (PQntuples(res) != 1)
16782         {
16783                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16784                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16785                                                                  PQntuples(res)),
16786                                   tbinfo->dobj.name, PQntuples(res));
16787                 exit_nicely(1);
16788         }
16789
16790         last = PQgetvalue(res, 0, 0);
16791         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
16792
16793         resetPQExpBuffer(query);
16794         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
16795         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
16796         appendPQExpBuffer(query, ", %s, %s);\n",
16797                                           last, (called ? "true" : "false"));
16798
16799         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
16800                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16801                                          tbinfo->dobj.name,
16802                                          tbinfo->dobj.namespace->dobj.name,
16803                                          NULL,
16804                                          tbinfo->rolname,
16805                                          false, "SEQUENCE SET", SECTION_DATA,
16806                                          query->data, "", NULL,
16807                                          &(tbinfo->dobj.dumpId), 1,
16808                                          NULL, NULL);
16809
16810         PQclear(res);
16811
16812         destroyPQExpBuffer(query);
16813 }
16814
16815 /*
16816  * dumpTrigger
16817  *        write the declaration of one user-defined table trigger
16818  */
16819 static void
16820 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
16821 {
16822         DumpOptions *dopt = fout->dopt;
16823         TableInfo  *tbinfo = tginfo->tgtable;
16824         PQExpBuffer query;
16825         PQExpBuffer delqry;
16826         PQExpBuffer trigprefix;
16827         char       *qtabname;
16828         char       *tgargs;
16829         size_t          lentgargs;
16830         const char *p;
16831         int                     findx;
16832         char       *tag;
16833
16834         /*
16835          * we needn't check dobj.dump because TriggerInfo wouldn't have been
16836          * created in the first place for non-dumpable triggers
16837          */
16838         if (dopt->dataOnly)
16839                 return;
16840
16841         query = createPQExpBuffer();
16842         delqry = createPQExpBuffer();
16843         trigprefix = createPQExpBuffer();
16844
16845         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16846
16847         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
16848                                           fmtId(tginfo->dobj.name));
16849         appendPQExpBuffer(delqry, "ON %s;\n",
16850                                           fmtQualifiedDumpable(tbinfo));
16851
16852         if (tginfo->tgdef)
16853         {
16854                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
16855         }
16856         else
16857         {
16858                 if (tginfo->tgisconstraint)
16859                 {
16860                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
16861                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
16862                 }
16863                 else
16864                 {
16865                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
16866                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
16867                 }
16868                 appendPQExpBufferStr(query, "\n    ");
16869
16870                 /* Trigger type */
16871                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
16872                         appendPQExpBufferStr(query, "BEFORE");
16873                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
16874                         appendPQExpBufferStr(query, "AFTER");
16875                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
16876                         appendPQExpBufferStr(query, "INSTEAD OF");
16877                 else
16878                 {
16879                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
16880                         exit_nicely(1);
16881                 }
16882
16883                 findx = 0;
16884                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
16885                 {
16886                         appendPQExpBufferStr(query, " INSERT");
16887                         findx++;
16888                 }
16889                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
16890                 {
16891                         if (findx > 0)
16892                                 appendPQExpBufferStr(query, " OR DELETE");
16893                         else
16894                                 appendPQExpBufferStr(query, " DELETE");
16895                         findx++;
16896                 }
16897                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
16898                 {
16899                         if (findx > 0)
16900                                 appendPQExpBufferStr(query, " OR UPDATE");
16901                         else
16902                                 appendPQExpBufferStr(query, " UPDATE");
16903                         findx++;
16904                 }
16905                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
16906                 {
16907                         if (findx > 0)
16908                                 appendPQExpBufferStr(query, " OR TRUNCATE");
16909                         else
16910                                 appendPQExpBufferStr(query, " TRUNCATE");
16911                         findx++;
16912                 }
16913                 appendPQExpBuffer(query, " ON %s\n",
16914                                                   fmtQualifiedDumpable(tbinfo));
16915
16916                 if (tginfo->tgisconstraint)
16917                 {
16918                         if (OidIsValid(tginfo->tgconstrrelid))
16919                         {
16920                                 /* regclass output is already quoted */
16921                                 appendPQExpBuffer(query, "    FROM %s\n    ",
16922                                                                   tginfo->tgconstrrelname);
16923                         }
16924                         if (!tginfo->tgdeferrable)
16925                                 appendPQExpBufferStr(query, "NOT ");
16926                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
16927                         if (tginfo->tginitdeferred)
16928                                 appendPQExpBufferStr(query, "DEFERRED\n");
16929                         else
16930                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
16931                 }
16932
16933                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
16934                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
16935                 else
16936                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
16937
16938                 /* regproc output is already sufficiently quoted */
16939                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
16940                                                   tginfo->tgfname);
16941
16942                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
16943                                                                                   &lentgargs);
16944                 p = tgargs;
16945                 for (findx = 0; findx < tginfo->tgnargs; findx++)
16946                 {
16947                         /* find the embedded null that terminates this trigger argument */
16948                         size_t          tlen = strlen(p);
16949
16950                         if (p + tlen >= tgargs + lentgargs)
16951                         {
16952                                 /* hm, not found before end of bytea value... */
16953                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
16954                                                   tginfo->tgargs,
16955                                                   tginfo->dobj.name,
16956                                                   tbinfo->dobj.name);
16957                                 exit_nicely(1);
16958                         }
16959
16960                         if (findx > 0)
16961                                 appendPQExpBufferStr(query, ", ");
16962                         appendStringLiteralAH(query, p, fout);
16963                         p += tlen + 1;
16964                 }
16965                 free(tgargs);
16966                 appendPQExpBufferStr(query, ");\n");
16967         }
16968
16969         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
16970         {
16971                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
16972                                                   fmtQualifiedDumpable(tbinfo));
16973                 switch (tginfo->tgenabled)
16974                 {
16975                         case 'D':
16976                         case 'f':
16977                                 appendPQExpBufferStr(query, "DISABLE");
16978                                 break;
16979                         case 'A':
16980                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
16981                                 break;
16982                         case 'R':
16983                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
16984                                 break;
16985                         default:
16986                                 appendPQExpBufferStr(query, "ENABLE");
16987                                 break;
16988                 }
16989                 appendPQExpBuffer(query, " TRIGGER %s;\n",
16990                                                   fmtId(tginfo->dobj.name));
16991         }
16992
16993         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
16994                                           fmtId(tginfo->dobj.name));
16995
16996         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
16997
16998         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16999                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17000                                          tag,
17001                                          tbinfo->dobj.namespace->dobj.name,
17002                                          NULL,
17003                                          tbinfo->rolname, false,
17004                                          "TRIGGER", SECTION_POST_DATA,
17005                                          query->data, delqry->data, NULL,
17006                                          NULL, 0,
17007                                          NULL, NULL);
17008
17009         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17010                 dumpComment(fout, trigprefix->data, qtabname,
17011                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17012                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17013
17014         free(tag);
17015         destroyPQExpBuffer(query);
17016         destroyPQExpBuffer(delqry);
17017         destroyPQExpBuffer(trigprefix);
17018         free(qtabname);
17019 }
17020
17021 /*
17022  * dumpEventTrigger
17023  *        write the declaration of one user-defined event trigger
17024  */
17025 static void
17026 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17027 {
17028         DumpOptions *dopt = fout->dopt;
17029         PQExpBuffer query;
17030         PQExpBuffer delqry;
17031         char       *qevtname;
17032
17033         /* Skip if not to be dumped */
17034         if (!evtinfo->dobj.dump || dopt->dataOnly)
17035                 return;
17036
17037         query = createPQExpBuffer();
17038         delqry = createPQExpBuffer();
17039
17040         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17041
17042         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17043         appendPQExpBufferStr(query, qevtname);
17044         appendPQExpBufferStr(query, " ON ");
17045         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17046
17047         if (strcmp("", evtinfo->evttags) != 0)
17048         {
17049                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17050                 appendPQExpBufferStr(query, evtinfo->evttags);
17051                 appendPQExpBufferChar(query, ')');
17052         }
17053
17054         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
17055         appendPQExpBufferStr(query, evtinfo->evtfname);
17056         appendPQExpBufferStr(query, "();\n");
17057
17058         if (evtinfo->evtenabled != 'O')
17059         {
17060                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17061                                                   qevtname);
17062                 switch (evtinfo->evtenabled)
17063                 {
17064                         case 'D':
17065                                 appendPQExpBufferStr(query, "DISABLE");
17066                                 break;
17067                         case 'A':
17068                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17069                                 break;
17070                         case 'R':
17071                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17072                                 break;
17073                         default:
17074                                 appendPQExpBufferStr(query, "ENABLE");
17075                                 break;
17076                 }
17077                 appendPQExpBufferStr(query, ";\n");
17078         }
17079
17080         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17081                                           qevtname);
17082
17083         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17084                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17085                                          evtinfo->dobj.name, NULL, NULL,
17086                                          evtinfo->evtowner, false,
17087                                          "EVENT TRIGGER", SECTION_POST_DATA,
17088                                          query->data, delqry->data, NULL,
17089                                          NULL, 0,
17090                                          NULL, NULL);
17091
17092         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17093                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17094                                         NULL, evtinfo->evtowner,
17095                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17096
17097         destroyPQExpBuffer(query);
17098         destroyPQExpBuffer(delqry);
17099         free(qevtname);
17100 }
17101
17102 /*
17103  * dumpRule
17104  *              Dump a rule
17105  */
17106 static void
17107 dumpRule(Archive *fout, RuleInfo *rinfo)
17108 {
17109         DumpOptions *dopt = fout->dopt;
17110         TableInfo  *tbinfo = rinfo->ruletable;
17111         bool            is_view;
17112         PQExpBuffer query;
17113         PQExpBuffer cmd;
17114         PQExpBuffer delcmd;
17115         PQExpBuffer ruleprefix;
17116         char       *qtabname;
17117         PGresult   *res;
17118         char       *tag;
17119
17120         /* Skip if not to be dumped */
17121         if (!rinfo->dobj.dump || dopt->dataOnly)
17122                 return;
17123
17124         /*
17125          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17126          * we do not want to dump it as a separate object.
17127          */
17128         if (!rinfo->separate)
17129                 return;
17130
17131         /*
17132          * If it's an ON SELECT rule, we want to print it as a view definition,
17133          * instead of a rule.
17134          */
17135         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17136
17137         query = createPQExpBuffer();
17138         cmd = createPQExpBuffer();
17139         delcmd = createPQExpBuffer();
17140         ruleprefix = createPQExpBuffer();
17141
17142         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17143
17144         if (is_view)
17145         {
17146                 PQExpBuffer result;
17147
17148                 /*
17149                  * We need OR REPLACE here because we'll be replacing a dummy view.
17150                  * Otherwise this should look largely like the regular view dump code.
17151                  */
17152                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17153                                                   fmtQualifiedDumpable(tbinfo));
17154                 if (nonemptyReloptions(tbinfo->reloptions))
17155                 {
17156                         appendPQExpBufferStr(cmd, " WITH (");
17157                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17158                         appendPQExpBufferChar(cmd, ')');
17159                 }
17160                 result = createViewAsClause(fout, tbinfo);
17161                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17162                 destroyPQExpBuffer(result);
17163                 if (tbinfo->checkoption != NULL)
17164                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17165                                                           tbinfo->checkoption);
17166                 appendPQExpBufferStr(cmd, ";\n");
17167         }
17168         else
17169         {
17170                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17171                 appendPQExpBuffer(query,
17172                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17173                                                   rinfo->dobj.catId.oid);
17174
17175                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17176
17177                 if (PQntuples(res) != 1)
17178                 {
17179                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17180                                           rinfo->dobj.name, tbinfo->dobj.name);
17181                         exit_nicely(1);
17182                 }
17183
17184                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17185
17186                 PQclear(res);
17187         }
17188
17189         /*
17190          * Add the command to alter the rules replication firing semantics if it
17191          * differs from the default.
17192          */
17193         if (rinfo->ev_enabled != 'O')
17194         {
17195                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17196                 switch (rinfo->ev_enabled)
17197                 {
17198                         case 'A':
17199                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17200                                                                   fmtId(rinfo->dobj.name));
17201                                 break;
17202                         case 'R':
17203                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17204                                                                   fmtId(rinfo->dobj.name));
17205                                 break;
17206                         case 'D':
17207                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17208                                                                   fmtId(rinfo->dobj.name));
17209                                 break;
17210                 }
17211         }
17212
17213         if (is_view)
17214         {
17215                 /*
17216                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17217                  * REPLACE VIEW to replace the rule with something with minimal
17218                  * dependencies.
17219                  */
17220                 PQExpBuffer result;
17221
17222                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17223                                                   fmtQualifiedDumpable(tbinfo));
17224                 result = createDummyViewAsClause(fout, tbinfo);
17225                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17226                 destroyPQExpBuffer(result);
17227         }
17228         else
17229         {
17230                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17231                                                   fmtId(rinfo->dobj.name));
17232                 appendPQExpBuffer(delcmd, "ON %s;\n",
17233                                                   fmtQualifiedDumpable(tbinfo));
17234         }
17235
17236         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17237                                           fmtId(rinfo->dobj.name));
17238
17239         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17240
17241         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17242                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17243                                          tag,
17244                                          tbinfo->dobj.namespace->dobj.name,
17245                                          NULL,
17246                                          tbinfo->rolname, false,
17247                                          "RULE", SECTION_POST_DATA,
17248                                          cmd->data, delcmd->data, NULL,
17249                                          NULL, 0,
17250                                          NULL, NULL);
17251
17252         /* Dump rule comments */
17253         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17254                 dumpComment(fout, ruleprefix->data, qtabname,
17255                                         tbinfo->dobj.namespace->dobj.name,
17256                                         tbinfo->rolname,
17257                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17258
17259         free(tag);
17260         destroyPQExpBuffer(query);
17261         destroyPQExpBuffer(cmd);
17262         destroyPQExpBuffer(delcmd);
17263         destroyPQExpBuffer(ruleprefix);
17264         free(qtabname);
17265 }
17266
17267 /*
17268  * getExtensionMembership --- obtain extension membership data
17269  *
17270  * We need to identify objects that are extension members as soon as they're
17271  * loaded, so that we can correctly determine whether they need to be dumped.
17272  * Generally speaking, extension member objects will get marked as *not* to
17273  * be dumped, as they will be recreated by the single CREATE EXTENSION
17274  * command.  However, in binary upgrade mode we still need to dump the members
17275  * individually.
17276  */
17277 void
17278 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17279                                            int numExtensions)
17280 {
17281         PQExpBuffer query;
17282         PGresult   *res;
17283         int                     ntups,
17284                                 nextmembers,
17285                                 i;
17286         int                     i_classid,
17287                                 i_objid,
17288                                 i_refobjid;
17289         ExtensionMemberId *extmembers;
17290         ExtensionInfo *ext;
17291
17292         /* Nothing to do if no extensions */
17293         if (numExtensions == 0)
17294                 return;
17295
17296         query = createPQExpBuffer();
17297
17298         /* refclassid constraint is redundant but may speed the search */
17299         appendPQExpBufferStr(query, "SELECT "
17300                                                  "classid, objid, refobjid "
17301                                                  "FROM pg_depend "
17302                                                  "WHERE refclassid = 'pg_extension'::regclass "
17303                                                  "AND deptype = 'e' "
17304                                                  "ORDER BY 3");
17305
17306         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17307
17308         ntups = PQntuples(res);
17309
17310         i_classid = PQfnumber(res, "classid");
17311         i_objid = PQfnumber(res, "objid");
17312         i_refobjid = PQfnumber(res, "refobjid");
17313
17314         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17315         nextmembers = 0;
17316
17317         /*
17318          * Accumulate data into extmembers[].
17319          *
17320          * Since we ordered the SELECT by referenced ID, we can expect that
17321          * multiple entries for the same extension will appear together; this
17322          * saves on searches.
17323          */
17324         ext = NULL;
17325
17326         for (i = 0; i < ntups; i++)
17327         {
17328                 CatalogId       objId;
17329                 Oid                     extId;
17330
17331                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17332                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17333                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17334
17335                 if (ext == NULL ||
17336                         ext->dobj.catId.oid != extId)
17337                         ext = findExtensionByOid(extId);
17338
17339                 if (ext == NULL)
17340                 {
17341                         /* shouldn't happen */
17342                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17343                         continue;
17344                 }
17345
17346                 extmembers[nextmembers].catId = objId;
17347                 extmembers[nextmembers].ext = ext;
17348                 nextmembers++;
17349         }
17350
17351         PQclear(res);
17352
17353         /* Remember the data for use later */
17354         setExtensionMembership(extmembers, nextmembers);
17355
17356         destroyPQExpBuffer(query);
17357 }
17358
17359 /*
17360  * processExtensionTables --- deal with extension configuration tables
17361  *
17362  * There are two parts to this process:
17363  *
17364  * 1. Identify and create dump records for extension configuration tables.
17365  *
17366  *        Extensions can mark tables as "configuration", which means that the user
17367  *        is able and expected to modify those tables after the extension has been
17368  *        loaded.  For these tables, we dump out only the data- the structure is
17369  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17370  *        foreign keys, which brings us to-
17371  *
17372  * 2. Record FK dependencies between configuration tables.
17373  *
17374  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17375  *        the data is loaded, we have to work out what the best order for reloading
17376  *        the data is, to avoid FK violations when the tables are restored.  This is
17377  *        not perfect- we can't handle circular dependencies and if any exist they
17378  *        will cause an invalid dump to be produced (though at least all of the data
17379  *        is included for a user to manually restore).  This is currently documented
17380  *        but perhaps we can provide a better solution in the future.
17381  */
17382 void
17383 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17384                                            int numExtensions)
17385 {
17386         DumpOptions *dopt = fout->dopt;
17387         PQExpBuffer query;
17388         PGresult   *res;
17389         int                     ntups,
17390                                 i;
17391         int                     i_conrelid,
17392                                 i_confrelid;
17393
17394         /* Nothing to do if no extensions */
17395         if (numExtensions == 0)
17396                 return;
17397
17398         /*
17399          * Identify extension configuration tables and create TableDataInfo
17400          * objects for them, ensuring their data will be dumped even though the
17401          * tables themselves won't be.
17402          *
17403          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17404          * user data in a configuration table is treated like schema data. This
17405          * seems appropriate since system data in a config table would get
17406          * reloaded by CREATE EXTENSION.
17407          */
17408         for (i = 0; i < numExtensions; i++)
17409         {
17410                 ExtensionInfo *curext = &(extinfo[i]);
17411                 char       *extconfig = curext->extconfig;
17412                 char       *extcondition = curext->extcondition;
17413                 char      **extconfigarray = NULL;
17414                 char      **extconditionarray = NULL;
17415                 int                     nconfigitems;
17416                 int                     nconditionitems;
17417
17418                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17419                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17420                         nconfigitems == nconditionitems)
17421                 {
17422                         int                     j;
17423
17424                         for (j = 0; j < nconfigitems; j++)
17425                         {
17426                                 TableInfo  *configtbl;
17427                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17428                                 bool            dumpobj =
17429                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17430
17431                                 configtbl = findTableByOid(configtbloid);
17432                                 if (configtbl == NULL)
17433                                         continue;
17434
17435                                 /*
17436                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17437                                  * unless the table or its schema is explicitly included
17438                                  */
17439                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17440                                 {
17441                                         /* check table explicitly requested */
17442                                         if (table_include_oids.head != NULL &&
17443                                                 simple_oid_list_member(&table_include_oids,
17444                                                                                            configtbloid))
17445                                                 dumpobj = true;
17446
17447                                         /* check table's schema explicitly requested */
17448                                         if (configtbl->dobj.namespace->dobj.dump &
17449                                                 DUMP_COMPONENT_DATA)
17450                                                 dumpobj = true;
17451                                 }
17452
17453                                 /* check table excluded by an exclusion switch */
17454                                 if (table_exclude_oids.head != NULL &&
17455                                         simple_oid_list_member(&table_exclude_oids,
17456                                                                                    configtbloid))
17457                                         dumpobj = false;
17458
17459                                 /* check schema excluded by an exclusion switch */
17460                                 if (simple_oid_list_member(&schema_exclude_oids,
17461                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17462                                         dumpobj = false;
17463
17464                                 if (dumpobj)
17465                                 {
17466                                         /*
17467                                          * Note: config tables are dumped without OIDs regardless
17468                                          * of the --oids setting.  This is because row filtering
17469                                          * conditions aren't compatible with dumping OIDs.
17470                                          */
17471                                         makeTableDataInfo(dopt, configtbl, false);
17472                                         if (configtbl->dataObj != NULL)
17473                                         {
17474                                                 if (strlen(extconditionarray[j]) > 0)
17475                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17476                                         }
17477                                 }
17478                         }
17479                 }
17480                 if (extconfigarray)
17481                         free(extconfigarray);
17482                 if (extconditionarray)
17483                         free(extconditionarray);
17484         }
17485
17486         /*
17487          * Now that all the TableInfoData objects have been created for all the
17488          * extensions, check their FK dependencies and register them to try and
17489          * dump the data out in an order that they can be restored in.
17490          *
17491          * Note that this is not a problem for user tables as their FKs are
17492          * recreated after the data has been loaded.
17493          */
17494
17495         query = createPQExpBuffer();
17496
17497         printfPQExpBuffer(query,
17498                                           "SELECT conrelid, confrelid "
17499                                           "FROM pg_constraint "
17500                                           "JOIN pg_depend ON (objid = confrelid) "
17501                                           "WHERE contype = 'f' "
17502                                           "AND refclassid = 'pg_extension'::regclass "
17503                                           "AND classid = 'pg_class'::regclass;");
17504
17505         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17506         ntups = PQntuples(res);
17507
17508         i_conrelid = PQfnumber(res, "conrelid");
17509         i_confrelid = PQfnumber(res, "confrelid");
17510
17511         /* Now get the dependencies and register them */
17512         for (i = 0; i < ntups; i++)
17513         {
17514                 Oid                     conrelid,
17515                                         confrelid;
17516                 TableInfo  *reftable,
17517                                    *contable;
17518
17519                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17520                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17521                 contable = findTableByOid(conrelid);
17522                 reftable = findTableByOid(confrelid);
17523
17524                 if (reftable == NULL ||
17525                         reftable->dataObj == NULL ||
17526                         contable == NULL ||
17527                         contable->dataObj == NULL)
17528                         continue;
17529
17530                 /*
17531                  * Make referencing TABLE_DATA object depend on the referenced table's
17532                  * TABLE_DATA object.
17533                  */
17534                 addObjectDependency(&contable->dataObj->dobj,
17535                                                         reftable->dataObj->dobj.dumpId);
17536         }
17537         PQclear(res);
17538         destroyPQExpBuffer(query);
17539 }
17540
17541 /*
17542  * getDependencies --- obtain available dependency data
17543  */
17544 static void
17545 getDependencies(Archive *fout)
17546 {
17547         PQExpBuffer query;
17548         PGresult   *res;
17549         int                     ntups,
17550                                 i;
17551         int                     i_classid,
17552                                 i_objid,
17553                                 i_refclassid,
17554                                 i_refobjid,
17555                                 i_deptype;
17556         DumpableObject *dobj,
17557                            *refdobj;
17558
17559         if (g_verbose)
17560                 write_msg(NULL, "reading dependency data\n");
17561
17562         query = createPQExpBuffer();
17563
17564         /*
17565          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17566          * already processed by getExtensionMembership.
17567          */
17568         appendPQExpBufferStr(query, "SELECT "
17569                                                  "classid, objid, refclassid, refobjid, deptype "
17570                                                  "FROM pg_depend "
17571                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17572                                                  "ORDER BY 1,2");
17573
17574         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17575
17576         ntups = PQntuples(res);
17577
17578         i_classid = PQfnumber(res, "classid");
17579         i_objid = PQfnumber(res, "objid");
17580         i_refclassid = PQfnumber(res, "refclassid");
17581         i_refobjid = PQfnumber(res, "refobjid");
17582         i_deptype = PQfnumber(res, "deptype");
17583
17584         /*
17585          * Since we ordered the SELECT by referencing ID, we can expect that
17586          * multiple entries for the same object will appear together; this saves
17587          * on searches.
17588          */
17589         dobj = NULL;
17590
17591         for (i = 0; i < ntups; i++)
17592         {
17593                 CatalogId       objId;
17594                 CatalogId       refobjId;
17595                 char            deptype;
17596
17597                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17598                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17599                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17600                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17601                 deptype = *(PQgetvalue(res, i, i_deptype));
17602
17603                 if (dobj == NULL ||
17604                         dobj->catId.tableoid != objId.tableoid ||
17605                         dobj->catId.oid != objId.oid)
17606                         dobj = findObjectByCatalogId(objId);
17607
17608                 /*
17609                  * Failure to find objects mentioned in pg_depend is not unexpected,
17610                  * since for example we don't collect info about TOAST tables.
17611                  */
17612                 if (dobj == NULL)
17613                 {
17614 #ifdef NOT_USED
17615                         fprintf(stderr, "no referencing object %u %u\n",
17616                                         objId.tableoid, objId.oid);
17617 #endif
17618                         continue;
17619                 }
17620
17621                 refdobj = findObjectByCatalogId(refobjId);
17622
17623                 if (refdobj == NULL)
17624                 {
17625 #ifdef NOT_USED
17626                         fprintf(stderr, "no referenced object %u %u\n",
17627                                         refobjId.tableoid, refobjId.oid);
17628 #endif
17629                         continue;
17630                 }
17631
17632                 /*
17633                  * Ordinarily, table rowtypes have implicit dependencies on their
17634                  * tables.  However, for a composite type the implicit dependency goes
17635                  * the other way in pg_depend; which is the right thing for DROP but
17636                  * it doesn't produce the dependency ordering we need. So in that one
17637                  * case, we reverse the direction of the dependency.
17638                  */
17639                 if (deptype == 'i' &&
17640                         dobj->objType == DO_TABLE &&
17641                         refdobj->objType == DO_TYPE)
17642                         addObjectDependency(refdobj, dobj->dumpId);
17643                 else
17644                         /* normal case */
17645                         addObjectDependency(dobj, refdobj->dumpId);
17646         }
17647
17648         PQclear(res);
17649
17650         destroyPQExpBuffer(query);
17651 }
17652
17653
17654 /*
17655  * createBoundaryObjects - create dummy DumpableObjects to represent
17656  * dump section boundaries.
17657  */
17658 static DumpableObject *
17659 createBoundaryObjects(void)
17660 {
17661         DumpableObject *dobjs;
17662
17663         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17664
17665         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17666         dobjs[0].catId = nilCatalogId;
17667         AssignDumpId(dobjs + 0);
17668         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17669
17670         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17671         dobjs[1].catId = nilCatalogId;
17672         AssignDumpId(dobjs + 1);
17673         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17674
17675         return dobjs;
17676 }
17677
17678 /*
17679  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17680  * section boundaries.
17681  */
17682 static void
17683 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17684                                                 DumpableObject *boundaryObjs)
17685 {
17686         DumpableObject *preDataBound = boundaryObjs + 0;
17687         DumpableObject *postDataBound = boundaryObjs + 1;
17688         int                     i;
17689
17690         for (i = 0; i < numObjs; i++)
17691         {
17692                 DumpableObject *dobj = dobjs[i];
17693
17694                 /*
17695                  * The classification of object types here must match the SECTION_xxx
17696                  * values assigned during subsequent ArchiveEntry calls!
17697                  */
17698                 switch (dobj->objType)
17699                 {
17700                         case DO_NAMESPACE:
17701                         case DO_EXTENSION:
17702                         case DO_TYPE:
17703                         case DO_SHELL_TYPE:
17704                         case DO_FUNC:
17705                         case DO_AGG:
17706                         case DO_OPERATOR:
17707                         case DO_ACCESS_METHOD:
17708                         case DO_OPCLASS:
17709                         case DO_OPFAMILY:
17710                         case DO_COLLATION:
17711                         case DO_CONVERSION:
17712                         case DO_TABLE:
17713                         case DO_ATTRDEF:
17714                         case DO_PROCLANG:
17715                         case DO_CAST:
17716                         case DO_DUMMY_TYPE:
17717                         case DO_TSPARSER:
17718                         case DO_TSDICT:
17719                         case DO_TSTEMPLATE:
17720                         case DO_TSCONFIG:
17721                         case DO_FDW:
17722                         case DO_FOREIGN_SERVER:
17723                         case DO_TRANSFORM:
17724                         case DO_BLOB:
17725                                 /* Pre-data objects: must come before the pre-data boundary */
17726                                 addObjectDependency(preDataBound, dobj->dumpId);
17727                                 break;
17728                         case DO_TABLE_DATA:
17729                         case DO_SEQUENCE_SET:
17730                         case DO_BLOB_DATA:
17731                                 /* Data objects: must come between the boundaries */
17732                                 addObjectDependency(dobj, preDataBound->dumpId);
17733                                 addObjectDependency(postDataBound, dobj->dumpId);
17734                                 break;
17735                         case DO_INDEX:
17736                         case DO_INDEX_ATTACH:
17737                         case DO_STATSEXT:
17738                         case DO_REFRESH_MATVIEW:
17739                         case DO_TRIGGER:
17740                         case DO_EVENT_TRIGGER:
17741                         case DO_DEFAULT_ACL:
17742                         case DO_POLICY:
17743                         case DO_PUBLICATION:
17744                         case DO_PUBLICATION_REL:
17745                         case DO_SUBSCRIPTION:
17746                                 /* Post-data objects: must come after the post-data boundary */
17747                                 addObjectDependency(dobj, postDataBound->dumpId);
17748                                 break;
17749                         case DO_RULE:
17750                                 /* Rules are post-data, but only if dumped separately */
17751                                 if (((RuleInfo *) dobj)->separate)
17752                                         addObjectDependency(dobj, postDataBound->dumpId);
17753                                 break;
17754                         case DO_CONSTRAINT:
17755                         case DO_FK_CONSTRAINT:
17756                                 /* Constraints are post-data, but only if dumped separately */
17757                                 if (((ConstraintInfo *) dobj)->separate)
17758                                         addObjectDependency(dobj, postDataBound->dumpId);
17759                                 break;
17760                         case DO_PRE_DATA_BOUNDARY:
17761                                 /* nothing to do */
17762                                 break;
17763                         case DO_POST_DATA_BOUNDARY:
17764                                 /* must come after the pre-data boundary */
17765                                 addObjectDependency(dobj, preDataBound->dumpId);
17766                                 break;
17767                 }
17768         }
17769 }
17770
17771
17772 /*
17773  * BuildArchiveDependencies - create dependency data for archive TOC entries
17774  *
17775  * The raw dependency data obtained by getDependencies() is not terribly
17776  * useful in an archive dump, because in many cases there are dependency
17777  * chains linking through objects that don't appear explicitly in the dump.
17778  * For example, a view will depend on its _RETURN rule while the _RETURN rule
17779  * will depend on other objects --- but the rule will not appear as a separate
17780  * object in the dump.  We need to adjust the view's dependencies to include
17781  * whatever the rule depends on that is included in the dump.
17782  *
17783  * Just to make things more complicated, there are also "special" dependencies
17784  * such as the dependency of a TABLE DATA item on its TABLE, which we must
17785  * not rearrange because pg_restore knows that TABLE DATA only depends on
17786  * its table.  In these cases we must leave the dependencies strictly as-is
17787  * even if they refer to not-to-be-dumped objects.
17788  *
17789  * To handle this, the convention is that "special" dependencies are created
17790  * during ArchiveEntry calls, and an archive TOC item that has any such
17791  * entries will not be touched here.  Otherwise, we recursively search the
17792  * DumpableObject data structures to build the correct dependencies for each
17793  * archive TOC item.
17794  */
17795 static void
17796 BuildArchiveDependencies(Archive *fout)
17797 {
17798         ArchiveHandle *AH = (ArchiveHandle *) fout;
17799         TocEntry   *te;
17800
17801         /* Scan all TOC entries in the archive */
17802         for (te = AH->toc->next; te != AH->toc; te = te->next)
17803         {
17804                 DumpableObject *dobj;
17805                 DumpId     *dependencies;
17806                 int                     nDeps;
17807                 int                     allocDeps;
17808
17809                 /* No need to process entries that will not be dumped */
17810                 if (te->reqs == 0)
17811                         continue;
17812                 /* Ignore entries that already have "special" dependencies */
17813                 if (te->nDeps > 0)
17814                         continue;
17815                 /* Otherwise, look up the item's original DumpableObject, if any */
17816                 dobj = findObjectByDumpId(te->dumpId);
17817                 if (dobj == NULL)
17818                         continue;
17819                 /* No work if it has no dependencies */
17820                 if (dobj->nDeps <= 0)
17821                         continue;
17822                 /* Set up work array */
17823                 allocDeps = 64;
17824                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
17825                 nDeps = 0;
17826                 /* Recursively find all dumpable dependencies */
17827                 findDumpableDependencies(AH, dobj,
17828                                                                  &dependencies, &nDeps, &allocDeps);
17829                 /* And save 'em ... */
17830                 if (nDeps > 0)
17831                 {
17832                         dependencies = (DumpId *) pg_realloc(dependencies,
17833                                                                                                  nDeps * sizeof(DumpId));
17834                         te->dependencies = dependencies;
17835                         te->nDeps = nDeps;
17836                 }
17837                 else
17838                         free(dependencies);
17839         }
17840 }
17841
17842 /* Recursive search subroutine for BuildArchiveDependencies */
17843 static void
17844 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
17845                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
17846 {
17847         int                     i;
17848
17849         /*
17850          * Ignore section boundary objects: if we search through them, we'll
17851          * report lots of bogus dependencies.
17852          */
17853         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
17854                 dobj->objType == DO_POST_DATA_BOUNDARY)
17855                 return;
17856
17857         for (i = 0; i < dobj->nDeps; i++)
17858         {
17859                 DumpId          depid = dobj->dependencies[i];
17860
17861                 if (TocIDRequired(AH, depid) != 0)
17862                 {
17863                         /* Object will be dumped, so just reference it as a dependency */
17864                         if (*nDeps >= *allocDeps)
17865                         {
17866                                 *allocDeps *= 2;
17867                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
17868                                                                                                           *allocDeps * sizeof(DumpId));
17869                         }
17870                         (*dependencies)[*nDeps] = depid;
17871                         (*nDeps)++;
17872                 }
17873                 else
17874                 {
17875                         /*
17876                          * Object will not be dumped, so recursively consider its deps. We
17877                          * rely on the assumption that sortDumpableObjects already broke
17878                          * any dependency loops, else we might recurse infinitely.
17879                          */
17880                         DumpableObject *otherdobj = findObjectByDumpId(depid);
17881
17882                         if (otherdobj)
17883                                 findDumpableDependencies(AH, otherdobj,
17884                                                                                  dependencies, nDeps, allocDeps);
17885                 }
17886         }
17887 }
17888
17889
17890 /*
17891  * getFormattedTypeName - retrieve a nicely-formatted type name for the
17892  * given type OID.
17893  *
17894  * This does not guarantee to schema-qualify the output, so it should not
17895  * be used to create the target object name for CREATE or ALTER commands.
17896  *
17897  * TODO: there might be some value in caching the results.
17898  */
17899 static char *
17900 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
17901 {
17902         char       *result;
17903         PQExpBuffer query;
17904         PGresult   *res;
17905
17906         if (oid == 0)
17907         {
17908                 if ((opts & zeroAsOpaque) != 0)
17909                         return pg_strdup(g_opaque_type);
17910                 else if ((opts & zeroAsAny) != 0)
17911                         return pg_strdup("'any'");
17912                 else if ((opts & zeroAsStar) != 0)
17913                         return pg_strdup("*");
17914                 else if ((opts & zeroAsNone) != 0)
17915                         return pg_strdup("NONE");
17916         }
17917
17918         query = createPQExpBuffer();
17919         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
17920                                           oid);
17921
17922         res = ExecuteSqlQueryForSingleRow(fout, query->data);
17923
17924         /* result of format_type is already quoted */
17925         result = pg_strdup(PQgetvalue(res, 0, 0));
17926
17927         PQclear(res);
17928         destroyPQExpBuffer(query);
17929
17930         return result;
17931 }
17932
17933 /*
17934  * Return a column list clause for the given relation.
17935  *
17936  * Special case: if there are no undropped columns in the relation, return
17937  * "", not an invalid "()" column list.
17938  */
17939 static const char *
17940 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
17941 {
17942         int                     numatts = ti->numatts;
17943         char      **attnames = ti->attnames;
17944         bool       *attisdropped = ti->attisdropped;
17945         bool            needComma;
17946         int                     i;
17947
17948         appendPQExpBufferChar(buffer, '(');
17949         needComma = false;
17950         for (i = 0; i < numatts; i++)
17951         {
17952                 if (attisdropped[i])
17953                         continue;
17954                 if (needComma)
17955                         appendPQExpBufferStr(buffer, ", ");
17956                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
17957                 needComma = true;
17958         }
17959
17960         if (!needComma)
17961                 return "";                              /* no undropped columns */
17962
17963         appendPQExpBufferChar(buffer, ')');
17964         return buffer->data;
17965 }
17966
17967 /*
17968  * Check if a reloptions array is nonempty.
17969  */
17970 static bool
17971 nonemptyReloptions(const char *reloptions)
17972 {
17973         /* Don't want to print it if it's just "{}" */
17974         return (reloptions != NULL && strlen(reloptions) > 2);
17975 }
17976
17977 /*
17978  * Format a reloptions array and append it to the given buffer.
17979  *
17980  * "prefix" is prepended to the option names; typically it's "" or "toast.".
17981  */
17982 static void
17983 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
17984                                                 const char *prefix, Archive *fout)
17985 {
17986         bool            res;
17987
17988         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
17989                                                                 fout->std_strings);
17990         if (!res)
17991                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
17992 }