]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Replace @postgresql.org with @lists.postgresql.org for mailinglists
[postgresql] / src / bin / pg_dump / pg_dump.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *        pg_dump is a utility for dumping out a postgres database
5  *        into a script file.
6  *
7  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to look at
18  *      the currently committed state.  So it is possible to get 'cache
19  *      lookup failed' error if someone performs DDL changes while a dump is
20  *      happening. The window for this sort of thing is from the acquisition
21  *      of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *      AccessShareLock on every table it intends to dump). It isn't very large,
23  *      but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres_fe.h"
33
34 #include <unistd.h>
35 #include <ctype.h>
36 #ifdef HAVE_TERMIOS_H
37 #include <termios.h>
38 #endif
39
40 #include "getopt_long.h"
41
42 #include "access/attnum.h"
43 #include "access/sysattr.h"
44 #include "access/transam.h"
45 #include "catalog/pg_aggregate_d.h"
46 #include "catalog/pg_am_d.h"
47 #include "catalog/pg_attribute_d.h"
48 #include "catalog/pg_cast_d.h"
49 #include "catalog/pg_class_d.h"
50 #include "catalog/pg_default_acl_d.h"
51 #include "catalog/pg_largeobject_d.h"
52 #include "catalog/pg_largeobject_metadata_d.h"
53 #include "catalog/pg_proc_d.h"
54 #include "catalog/pg_trigger_d.h"
55 #include "catalog/pg_type_d.h"
56 #include "libpq/libpq-fs.h"
57 #include "storage/block.h"
58
59 #include "dumputils.h"
60 #include "parallel.h"
61 #include "pg_backup_db.h"
62 #include "pg_backup_utils.h"
63 #include "pg_dump.h"
64 #include "fe_utils/connect.h"
65 #include "fe_utils/string_utils.h"
66
67
68 typedef struct
69 {
70         const char *descr;                      /* comment for an object */
71         Oid                     classoid;               /* object class (catalog OID) */
72         Oid                     objoid;                 /* object OID */
73         int                     objsubid;               /* subobject (table column #) */
74 } CommentItem;
75
76 typedef struct
77 {
78         const char *provider;           /* label provider of this security label */
79         const char *label;                      /* security label for an object */
80         Oid                     classoid;               /* object class (catalog OID) */
81         Oid                     objoid;                 /* object OID */
82         int                     objsubid;               /* subobject (table column #) */
83 } SecLabelItem;
84
85 typedef enum OidOptions
86 {
87         zeroAsOpaque = 1,
88         zeroAsAny = 2,
89         zeroAsStar = 4,
90         zeroAsNone = 8
91 } OidOptions;
92
93 /* global decls */
94 bool            g_verbose;                      /* User wants verbose narration of our
95                                                                  * activities. */
96 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
97
98 /* subquery used to convert user ID (eg, datdba) to user name */
99 static const char *username_subquery;
100
101 /*
102  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
103  * FirstNormalObjectId - 1.
104  */
105 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
106
107 /* The specified names/patterns should to match at least one entity */
108 static int      strict_names = 0;
109
110 /*
111  * Object inclusion/exclusion lists
112  *
113  * The string lists record the patterns given by command-line switches,
114  * which we then convert to lists of OIDs of matching objects.
115  */
116 static SimpleStringList schema_include_patterns = {NULL, NULL};
117 static SimpleOidList schema_include_oids = {NULL, NULL};
118 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
119 static SimpleOidList schema_exclude_oids = {NULL, NULL};
120
121 static SimpleStringList table_include_patterns = {NULL, NULL};
122 static SimpleOidList table_include_oids = {NULL, NULL};
123 static SimpleStringList table_exclude_patterns = {NULL, NULL};
124 static SimpleOidList table_exclude_oids = {NULL, NULL};
125 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
126 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
127
128
129 char            g_opaque_type[10];      /* name for the opaque type */
130
131 /* placeholders for the delimiters for comments */
132 char            g_comment_start[10];
133 char            g_comment_end[10];
134
135 static const CatalogId nilCatalogId = {0, 0};
136
137 /*
138  * Macro for producing quoted, schema-qualified name of a dumpable object.
139  */
140 #define fmtQualifiedDumpable(obj) \
141         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
142                                    (obj)->dobj.name)
143
144 static void help(const char *progname);
145 static void setup_connection(Archive *AH,
146                                  const char *dumpencoding, const char *dumpsnapshot,
147                                  char *use_role);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(Archive *fout,
150                                                         SimpleStringList *patterns,
151                                                         SimpleOidList *oids,
152                                                         bool strict_names);
153 static void expand_table_name_patterns(Archive *fout,
154                                                    SimpleStringList *patterns,
155                                                    SimpleOidList *oids,
156                                                    bool strict_names);
157 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
158 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
159 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
160 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
161 static void dumpComment(Archive *fout, const char *type, const char *name,
162                         const char *namespace, const char *owner,
163                         CatalogId catalogId, int subid, DumpId dumpId);
164 static int findComments(Archive *fout, Oid classoid, Oid objoid,
165                          CommentItem **items);
166 static int      collectComments(Archive *fout, CommentItem **items);
167 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
168                          const char *namespace, const char *owner,
169                          CatalogId catalogId, int subid, DumpId dumpId);
170 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
171                           SecLabelItem **items);
172 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
173 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
174 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
175 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
176 static void dumpType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
179 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
181 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
182 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
183 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
184 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
185 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
186 static void dumpFunc(Archive *fout, FuncInfo *finfo);
187 static void dumpCast(Archive *fout, CastInfo *cast);
188 static void dumpTransform(Archive *fout, TransformInfo *transform);
189 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
190 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
191 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
192 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
193 static void dumpCollation(Archive *fout, CollInfo *collinfo);
194 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
195 static void dumpRule(Archive *fout, RuleInfo *rinfo);
196 static void dumpAgg(Archive *fout, AggInfo *agginfo);
197 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
198 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
199 static void dumpTable(Archive *fout, TableInfo *tbinfo);
200 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
201 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
202 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
203 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
204 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
205 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
206 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
207 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
208 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
209 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
210 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
211 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
212 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
213 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
214 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
215 static void dumpUserMappings(Archive *fout,
216                                  const char *servername, const char *namespace,
217                                  const char *owner, CatalogId catalogId, DumpId dumpId);
218 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
219
220 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
221                 const char *type, const char *name, const char *subname,
222                 const char *nspname, const char *owner,
223                 const char *acls, const char *racls,
224                 const char *initacls, const char *initracls);
225
226 static void getDependencies(Archive *fout);
227 static void BuildArchiveDependencies(Archive *fout);
228 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
229                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
230
231 static DumpableObject *createBoundaryObjects(void);
232 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
233                                                 DumpableObject *boundaryObjs);
234
235 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
236 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
237 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
238 static void buildMatViewRefreshDependencies(Archive *fout);
239 static void getTableDataFKConstraints(void);
240 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
241                                                   bool is_agg);
242 static char *format_function_arguments_old(Archive *fout,
243                                                           FuncInfo *finfo, int nallargs,
244                                                           char **allargtypes,
245                                                           char **argmodes,
246                                                           char **argnames);
247 static char *format_function_signature(Archive *fout,
248                                                   FuncInfo *finfo, bool honor_quotes);
249 static char *convertRegProcReference(Archive *fout,
250                                                 const char *proc);
251 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
252 static char *convertTSFunction(Archive *fout, Oid funcOid);
253 static Oid      findLastBuiltinOid_V71(Archive *fout);
254 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
255 static void getBlobs(Archive *fout);
256 static void dumpBlob(Archive *fout, BlobInfo *binfo);
257 static int      dumpBlobs(Archive *fout, void *arg);
258 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
259 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
260 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
261 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
262 static void dumpDatabase(Archive *AH);
263 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
264                                    const char *dbname, Oid dboid);
265 static void dumpEncoding(Archive *AH);
266 static void dumpStdStrings(Archive *AH);
267 static void dumpSearchPath(Archive *AH);
268 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
269                                                                                  PQExpBuffer upgrade_buffer,
270                                                                                  Oid pg_type_oid,
271                                                                                  bool force_array_type);
272 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
273                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
274 static void binary_upgrade_set_pg_class_oids(Archive *fout,
275                                                                  PQExpBuffer upgrade_buffer,
276                                                                  Oid pg_class_oid, bool is_index);
277 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
278                                                                 DumpableObject *dobj,
279                                                                 const char *objtype,
280                                                                 const char *objname,
281                                                                 const char *objnamespace);
282 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
283 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
284 static bool nonemptyReloptions(const char *reloptions);
285 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
286                                                 const char *prefix, Archive *fout);
287 static char *get_synchronized_snapshot(Archive *fout);
288 static void setupDumpWorker(Archive *AHX);
289 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
290
291
292 int
293 main(int argc, char **argv)
294 {
295         int                     c;
296         const char *filename = NULL;
297         const char *format = "p";
298         TableInfo  *tblinfo;
299         int                     numTables;
300         DumpableObject **dobjs;
301         int                     numObjs;
302         DumpableObject *boundaryObjs;
303         int                     i;
304         int                     optindex;
305         RestoreOptions *ropt;
306         Archive    *fout;                       /* the script file */
307         const char *dumpencoding = NULL;
308         const char *dumpsnapshot = NULL;
309         char       *use_role = NULL;
310         int                     numWorkers = 1;
311         trivalue        prompt_password = TRI_DEFAULT;
312         int                     compressLevel = -1;
313         int                     plainText = 0;
314         ArchiveFormat archiveFormat = archUnknown;
315         ArchiveMode archiveMode;
316
317         static DumpOptions dopt;
318
319         static struct option long_options[] = {
320                 {"data-only", no_argument, NULL, 'a'},
321                 {"blobs", no_argument, NULL, 'b'},
322                 {"no-blobs", no_argument, NULL, 'B'},
323                 {"clean", no_argument, NULL, 'c'},
324                 {"create", no_argument, NULL, 'C'},
325                 {"dbname", required_argument, NULL, 'd'},
326                 {"file", required_argument, NULL, 'f'},
327                 {"format", required_argument, NULL, 'F'},
328                 {"host", required_argument, NULL, 'h'},
329                 {"jobs", 1, NULL, 'j'},
330                 {"no-reconnect", no_argument, NULL, 'R'},
331                 {"no-owner", no_argument, NULL, 'O'},
332                 {"port", required_argument, NULL, 'p'},
333                 {"schema", required_argument, NULL, 'n'},
334                 {"exclude-schema", required_argument, NULL, 'N'},
335                 {"schema-only", no_argument, NULL, 's'},
336                 {"superuser", required_argument, NULL, 'S'},
337                 {"table", required_argument, NULL, 't'},
338                 {"exclude-table", required_argument, NULL, 'T'},
339                 {"no-password", no_argument, NULL, 'w'},
340                 {"password", no_argument, NULL, 'W'},
341                 {"username", required_argument, NULL, 'U'},
342                 {"verbose", no_argument, NULL, 'v'},
343                 {"no-privileges", no_argument, NULL, 'x'},
344                 {"no-acl", no_argument, NULL, 'x'},
345                 {"compress", required_argument, NULL, 'Z'},
346                 {"encoding", required_argument, NULL, 'E'},
347                 {"help", no_argument, NULL, '?'},
348                 {"version", no_argument, NULL, 'V'},
349
350                 /*
351                  * the following options don't have an equivalent short option letter
352                  */
353                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
354                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
355                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
356                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
357                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
358                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
359                 {"exclude-table-data", required_argument, NULL, 4},
360                 {"if-exists", no_argument, &dopt.if_exists, 1},
361                 {"inserts", no_argument, &dopt.dump_inserts, 1},
362                 {"lock-wait-timeout", required_argument, NULL, 2},
363                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
364                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
365                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
366                 {"role", required_argument, NULL, 3},
367                 {"section", required_argument, NULL, 5},
368                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
369                 {"snapshot", required_argument, NULL, 6},
370                 {"strict-names", no_argument, &strict_names, 1},
371                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
372                 {"no-comments", no_argument, &dopt.no_comments, 1},
373                 {"no-publications", no_argument, &dopt.no_publications, 1},
374                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
375                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
376                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
377                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
378                 {"no-sync", no_argument, NULL, 7},
379                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
380
381                 {NULL, 0, NULL, 0}
382         };
383
384         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
385
386         /*
387          * Initialize what we need for parallel execution, especially for thread
388          * support on Windows.
389          */
390         init_parallel_dump_utils();
391
392         g_verbose = false;
393
394         strcpy(g_comment_start, "-- ");
395         g_comment_end[0] = '\0';
396         strcpy(g_opaque_type, "opaque");
397
398         progname = get_progname(argv[0]);
399
400         if (argc > 1)
401         {
402                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
403                 {
404                         help(progname);
405                         exit_nicely(0);
406                 }
407                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
408                 {
409                         puts("pg_dump (PostgreSQL) " PG_VERSION);
410                         exit_nicely(0);
411                 }
412         }
413
414         InitDumpOptions(&dopt);
415
416         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
417                                                         long_options, &optindex)) != -1)
418         {
419                 switch (c)
420                 {
421                         case 'a':                       /* Dump data only */
422                                 dopt.dataOnly = true;
423                                 break;
424
425                         case 'b':                       /* Dump blobs */
426                                 dopt.outputBlobs = true;
427                                 break;
428
429                         case 'B':                       /* Don't dump blobs */
430                                 dopt.dontOutputBlobs = true;
431                                 break;
432
433                         case 'c':                       /* clean (i.e., drop) schema prior to create */
434                                 dopt.outputClean = 1;
435                                 break;
436
437                         case 'C':                       /* Create DB */
438                                 dopt.outputCreateDB = 1;
439                                 break;
440
441                         case 'd':                       /* database name */
442                                 dopt.dbname = pg_strdup(optarg);
443                                 break;
444
445                         case 'E':                       /* Dump encoding */
446                                 dumpencoding = pg_strdup(optarg);
447                                 break;
448
449                         case 'f':
450                                 filename = pg_strdup(optarg);
451                                 break;
452
453                         case 'F':
454                                 format = pg_strdup(optarg);
455                                 break;
456
457                         case 'h':                       /* server host */
458                                 dopt.pghost = pg_strdup(optarg);
459                                 break;
460
461                         case 'j':                       /* number of dump jobs */
462                                 numWorkers = atoi(optarg);
463                                 break;
464
465                         case 'n':                       /* include schema(s) */
466                                 simple_string_list_append(&schema_include_patterns, optarg);
467                                 dopt.include_everything = false;
468                                 break;
469
470                         case 'N':                       /* exclude schema(s) */
471                                 simple_string_list_append(&schema_exclude_patterns, optarg);
472                                 break;
473
474                         case 'O':                       /* Don't reconnect to match owner */
475                                 dopt.outputNoOwner = 1;
476                                 break;
477
478                         case 'p':                       /* server port */
479                                 dopt.pgport = pg_strdup(optarg);
480                                 break;
481
482                         case 'R':
483                                 /* no-op, still accepted for backwards compatibility */
484                                 break;
485
486                         case 's':                       /* dump schema only */
487                                 dopt.schemaOnly = true;
488                                 break;
489
490                         case 'S':                       /* Username for superuser in plain text output */
491                                 dopt.outputSuperuser = pg_strdup(optarg);
492                                 break;
493
494                         case 't':                       /* include table(s) */
495                                 simple_string_list_append(&table_include_patterns, optarg);
496                                 dopt.include_everything = false;
497                                 break;
498
499                         case 'T':                       /* exclude table(s) */
500                                 simple_string_list_append(&table_exclude_patterns, optarg);
501                                 break;
502
503                         case 'U':
504                                 dopt.username = pg_strdup(optarg);
505                                 break;
506
507                         case 'v':                       /* verbose */
508                                 g_verbose = true;
509                                 break;
510
511                         case 'w':
512                                 prompt_password = TRI_NO;
513                                 break;
514
515                         case 'W':
516                                 prompt_password = TRI_YES;
517                                 break;
518
519                         case 'x':                       /* skip ACL dump */
520                                 dopt.aclsSkip = true;
521                                 break;
522
523                         case 'Z':                       /* Compression Level */
524                                 compressLevel = atoi(optarg);
525                                 if (compressLevel < 0 || compressLevel > 9)
526                                 {
527                                         write_msg(NULL, "compression level must be in range 0..9\n");
528                                         exit_nicely(1);
529                                 }
530                                 break;
531
532                         case 0:
533                                 /* This covers the long options. */
534                                 break;
535
536                         case 2:                         /* lock-wait-timeout */
537                                 dopt.lockWaitTimeout = pg_strdup(optarg);
538                                 break;
539
540                         case 3:                         /* SET ROLE */
541                                 use_role = pg_strdup(optarg);
542                                 break;
543
544                         case 4:                         /* exclude table(s) data */
545                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
546                                 break;
547
548                         case 5:                         /* section */
549                                 set_dump_section(optarg, &dopt.dumpSections);
550                                 break;
551
552                         case 6:                         /* snapshot */
553                                 dumpsnapshot = pg_strdup(optarg);
554                                 break;
555
556                         case 7:                         /* no-sync */
557                                 dosync = false;
558                                 break;
559
560                         default:
561                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
562                                 exit_nicely(1);
563                 }
564         }
565
566         /*
567          * Non-option argument specifies database name as long as it wasn't
568          * already specified with -d / --dbname
569          */
570         if (optind < argc && dopt.dbname == NULL)
571                 dopt.dbname = argv[optind++];
572
573         /* Complain if any arguments remain */
574         if (optind < argc)
575         {
576                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
577                                 progname, argv[optind]);
578                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
579                                 progname);
580                 exit_nicely(1);
581         }
582
583         /* --column-inserts implies --inserts */
584         if (dopt.column_inserts)
585                 dopt.dump_inserts = 1;
586
587         /*
588          * Binary upgrade mode implies dumping sequence data even in schema-only
589          * mode.  This is not exposed as a separate option, but kept separate
590          * internally for clarity.
591          */
592         if (dopt.binary_upgrade)
593                 dopt.sequence_data = 1;
594
595         if (dopt.dataOnly && dopt.schemaOnly)
596         {
597                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
598                 exit_nicely(1);
599         }
600
601         if (dopt.dataOnly && dopt.outputClean)
602         {
603                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
604                 exit_nicely(1);
605         }
606
607         if (dopt.if_exists && !dopt.outputClean)
608                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
609
610         if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
611                 exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
612
613         /* Identify archive format to emit */
614         archiveFormat = parseArchiveFormat(format, &archiveMode);
615
616         /* archiveFormat specific setup */
617         if (archiveFormat == archNull)
618                 plainText = 1;
619
620         /* Custom and directory formats are compressed by default, others not */
621         if (compressLevel == -1)
622         {
623 #ifdef HAVE_LIBZ
624                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
625                         compressLevel = Z_DEFAULT_COMPRESSION;
626                 else
627 #endif
628                         compressLevel = 0;
629         }
630
631 #ifndef HAVE_LIBZ
632         if (compressLevel != 0)
633                 write_msg(NULL, "WARNING: requested compression not available in this "
634                                   "installation -- archive will be uncompressed\n");
635         compressLevel = 0;
636 #endif
637
638         /*
639          * If emitting an archive format, we always want to emit a DATABASE item,
640          * in case --create is specified at pg_restore time.
641          */
642         if (!plainText)
643                 dopt.outputCreateDB = 1;
644
645         /*
646          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
647          * parallel jobs because that's the maximum limit for the
648          * WaitForMultipleObjects() call.
649          */
650         if (numWorkers <= 0
651 #ifdef WIN32
652                 || numWorkers > MAXIMUM_WAIT_OBJECTS
653 #endif
654                 )
655                 exit_horribly(NULL, "invalid number of parallel jobs\n");
656
657         /* Parallel backup only in the directory archive format so far */
658         if (archiveFormat != archDirectory && numWorkers > 1)
659                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
660
661         /* Open the output file */
662         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
663                                                  archiveMode, setupDumpWorker);
664
665         /* Make dump options accessible right away */
666         SetArchiveOptions(fout, &dopt, NULL);
667
668         /* Register the cleanup hook */
669         on_exit_close_archive(fout);
670
671         /* Let the archiver know how noisy to be */
672         fout->verbose = g_verbose;
673
674         /*
675          * We allow the server to be back to 8.0, and up to any minor release of
676          * our own major version.  (See also version check in pg_dumpall.c.)
677          */
678         fout->minRemoteVersion = 80000;
679         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
680
681         fout->numWorkers = numWorkers;
682
683         /*
684          * Open the database using the Archiver, so it knows about it. Errors mean
685          * death.
686          */
687         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
688         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
689
690         /*
691          * Disable security label support if server version < v9.1.x (prevents
692          * access to nonexistent pg_seclabel catalog)
693          */
694         if (fout->remoteVersion < 90100)
695                 dopt.no_security_labels = 1;
696
697         /*
698          * On hot standbys, never try to dump unlogged table data, since it will
699          * just throw an error.
700          */
701         if (fout->isStandby)
702                 dopt.no_unlogged_table_data = true;
703
704         /* Select the appropriate subquery to convert user IDs to names */
705         if (fout->remoteVersion >= 80100)
706                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
707         else
708                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
709
710         /* check the version for the synchronized snapshots feature */
711         if (numWorkers > 1 && fout->remoteVersion < 90200
712                 && !dopt.no_synchronized_snapshots)
713                 exit_horribly(NULL,
714                                           "Synchronized snapshots are not supported by this server version.\n"
715                                           "Run with --no-synchronized-snapshots instead if you do not need\n"
716                                           "synchronized snapshots.\n");
717
718         /* check the version when a snapshot is explicitly specified by user */
719         if (dumpsnapshot && fout->remoteVersion < 90200)
720                 exit_horribly(NULL,
721                                           "Exported snapshots are not supported by this server version.\n");
722
723         /*
724          * Find the last built-in OID, if needed (prior to 8.1)
725          *
726          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
727          */
728         if (fout->remoteVersion < 80100)
729                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
730         else
731                 g_last_builtin_oid = FirstNormalObjectId - 1;
732
733         if (g_verbose)
734                 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
735
736         /* Expand schema selection patterns into OID lists */
737         if (schema_include_patterns.head != NULL)
738         {
739                 expand_schema_name_patterns(fout, &schema_include_patterns,
740                                                                         &schema_include_oids,
741                                                                         strict_names);
742                 if (schema_include_oids.head == NULL)
743                         exit_horribly(NULL, "no matching schemas were found\n");
744         }
745         expand_schema_name_patterns(fout, &schema_exclude_patterns,
746                                                                 &schema_exclude_oids,
747                                                                 false);
748         /* non-matching exclusion patterns aren't an error */
749
750         /* Expand table selection patterns into OID lists */
751         if (table_include_patterns.head != NULL)
752         {
753                 expand_table_name_patterns(fout, &table_include_patterns,
754                                                                    &table_include_oids,
755                                                                    strict_names);
756                 if (table_include_oids.head == NULL)
757                         exit_horribly(NULL, "no matching tables were found\n");
758         }
759         expand_table_name_patterns(fout, &table_exclude_patterns,
760                                                            &table_exclude_oids,
761                                                            false);
762
763         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
764                                                            &tabledata_exclude_oids,
765                                                            false);
766
767         /* non-matching exclusion patterns aren't an error */
768
769         /*
770          * Dumping blobs is the default for dumps where an inclusion switch is not
771          * used (an "include everything" dump).  -B can be used to exclude blobs
772          * from those dumps.  -b can be used to include blobs even when an
773          * inclusion switch is used.
774          *
775          * -s means "schema only" and blobs are data, not schema, so we never
776          * include blobs when -s is used.
777          */
778         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
779                 dopt.outputBlobs = true;
780
781         /*
782          * Now scan the database and create DumpableObject structs for all the
783          * objects we intend to dump.
784          */
785         tblinfo = getSchemaData(fout, &numTables);
786
787         if (fout->remoteVersion < 80400)
788                 guessConstraintInheritance(tblinfo, numTables);
789
790         if (!dopt.schemaOnly)
791         {
792                 getTableData(&dopt, tblinfo, numTables, 0);
793                 buildMatViewRefreshDependencies(fout);
794                 if (dopt.dataOnly)
795                         getTableDataFKConstraints();
796         }
797
798         if (dopt.schemaOnly && dopt.sequence_data)
799                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
800
801         /*
802          * In binary-upgrade mode, we do not have to worry about the actual blob
803          * data or the associated metadata that resides in the pg_largeobject and
804          * pg_largeobject_metadata tables, respectively.
805          *
806          * However, we do need to collect blob information as there may be
807          * comments or other information on blobs that we do need to dump out.
808          */
809         if (dopt.outputBlobs || dopt.binary_upgrade)
810                 getBlobs(fout);
811
812         /*
813          * Collect dependency data to assist in ordering the objects.
814          */
815         getDependencies(fout);
816
817         /* Lastly, create dummy objects to represent the section boundaries */
818         boundaryObjs = createBoundaryObjects();
819
820         /* Get pointers to all the known DumpableObjects */
821         getDumpableObjects(&dobjs, &numObjs);
822
823         /*
824          * Add dummy dependencies to enforce the dump section ordering.
825          */
826         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
827
828         /*
829          * Sort the objects into a safe dump order (no forward references).
830          *
831          * We rely on dependency information to help us determine a safe order, so
832          * the initial sort is mostly for cosmetic purposes: we sort by name to
833          * ensure that logically identical schemas will dump identically.
834          */
835         sortDumpableObjectsByTypeName(dobjs, numObjs);
836
837         sortDumpableObjects(dobjs, numObjs,
838                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
839
840         /*
841          * Create archive TOC entries for all the objects to be dumped, in a safe
842          * order.
843          */
844
845         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
846         dumpEncoding(fout);
847         dumpStdStrings(fout);
848         dumpSearchPath(fout);
849
850         /* The database items are always next, unless we don't want them at all */
851         if (dopt.outputCreateDB)
852                 dumpDatabase(fout);
853
854         /* Now the rearrangeable objects. */
855         for (i = 0; i < numObjs; i++)
856                 dumpDumpableObject(fout, dobjs[i]);
857
858         /*
859          * Set up options info to ensure we dump what we want.
860          */
861         ropt = NewRestoreOptions();
862         ropt->filename = filename;
863
864         /* if you change this list, see dumpOptionsFromRestoreOptions */
865         ropt->dropSchema = dopt.outputClean;
866         ropt->dataOnly = dopt.dataOnly;
867         ropt->schemaOnly = dopt.schemaOnly;
868         ropt->if_exists = dopt.if_exists;
869         ropt->column_inserts = dopt.column_inserts;
870         ropt->dumpSections = dopt.dumpSections;
871         ropt->aclsSkip = dopt.aclsSkip;
872         ropt->superuser = dopt.outputSuperuser;
873         ropt->createDB = dopt.outputCreateDB;
874         ropt->noOwner = dopt.outputNoOwner;
875         ropt->noTablespace = dopt.outputNoTablespaces;
876         ropt->disable_triggers = dopt.disable_triggers;
877         ropt->use_setsessauth = dopt.use_setsessauth;
878         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
879         ropt->dump_inserts = dopt.dump_inserts;
880         ropt->no_comments = dopt.no_comments;
881         ropt->no_publications = dopt.no_publications;
882         ropt->no_security_labels = dopt.no_security_labels;
883         ropt->no_subscriptions = dopt.no_subscriptions;
884         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
885         ropt->include_everything = dopt.include_everything;
886         ropt->enable_row_security = dopt.enable_row_security;
887         ropt->sequence_data = dopt.sequence_data;
888         ropt->binary_upgrade = dopt.binary_upgrade;
889
890         if (compressLevel == -1)
891                 ropt->compression = 0;
892         else
893                 ropt->compression = compressLevel;
894
895         ropt->suppressDumpWarnings = true;      /* We've already shown them */
896
897         SetArchiveOptions(fout, &dopt, ropt);
898
899         /* Mark which entries should be output */
900         ProcessArchiveRestoreOptions(fout);
901
902         /*
903          * The archive's TOC entries are now marked as to which ones will actually
904          * be output, so we can set up their dependency lists properly. This isn't
905          * necessary for plain-text output, though.
906          */
907         if (!plainText)
908                 BuildArchiveDependencies(fout);
909
910         /*
911          * And finally we can do the actual output.
912          *
913          * Note: for non-plain-text output formats, the output file is written
914          * inside CloseArchive().  This is, um, bizarre; but not worth changing
915          * right now.
916          */
917         if (plainText)
918                 RestoreArchive(fout);
919
920         CloseArchive(fout);
921
922         exit_nicely(0);
923 }
924
925
926 static void
927 help(const char *progname)
928 {
929         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
930         printf(_("Usage:\n"));
931         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
932
933         printf(_("\nGeneral options:\n"));
934         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
935         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
936                          "                               plain text (default))\n"));
937         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
938         printf(_("  -v, --verbose                verbose mode\n"));
939         printf(_("  -V, --version                output version information, then exit\n"));
940         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
941         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
942         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
943         printf(_("  -?, --help                   show this help, then exit\n"));
944
945         printf(_("\nOptions controlling the output content:\n"));
946         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
947         printf(_("  -b, --blobs                  include large objects in dump\n"));
948         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
949         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
950         printf(_("  -C, --create                 include commands to create database in dump\n"));
951         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
952         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
953         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
954         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
955                          "                               plain-text format\n"));
956         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
957         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
958         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
959         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
960         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
961         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
962         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
963         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
964         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
965         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
966                          "                               access to)\n"));
967         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
968         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
969         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
970         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
971         printf(_("  --no-comments                do not dump comments\n"));
972         printf(_("  --no-publications            do not dump publications\n"));
973         printf(_("  --no-security-labels         do not dump security label assignments\n"));
974         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
975         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
976         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
977         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
978         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
979         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
980         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
981         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
982         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
983         printf(_("  --strict-names               require table and/or schema include patterns to\n"
984                          "                               match at least one entity each\n"));
985         printf(_("  --use-set-session-authorization\n"
986                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
987                          "                               ALTER OWNER commands to set ownership\n"));
988
989         printf(_("\nConnection options:\n"));
990         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
991         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
992         printf(_("  -p, --port=PORT          database server port number\n"));
993         printf(_("  -U, --username=NAME      connect as specified database user\n"));
994         printf(_("  -w, --no-password        never prompt for password\n"));
995         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
996         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
997
998         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
999                          "variable value is used.\n\n"));
1000         printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
1001 }
1002
1003 static void
1004 setup_connection(Archive *AH, const char *dumpencoding,
1005                                  const char *dumpsnapshot, char *use_role)
1006 {
1007         DumpOptions *dopt = AH->dopt;
1008         PGconn     *conn = GetConnection(AH);
1009         const char *std_strings;
1010
1011         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1012
1013         /*
1014          * Set the client encoding if requested.
1015          */
1016         if (dumpencoding)
1017         {
1018                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1019                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1020                                                   dumpencoding);
1021         }
1022
1023         /*
1024          * Get the active encoding and the standard_conforming_strings setting, so
1025          * we know how to escape strings.
1026          */
1027         AH->encoding = PQclientEncoding(conn);
1028
1029         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1030         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1031
1032         /*
1033          * Set the role if requested.  In a parallel dump worker, we'll be passed
1034          * use_role == NULL, but AH->use_role is already set (if user specified it
1035          * originally) and we should use that.
1036          */
1037         if (!use_role && AH->use_role)
1038                 use_role = AH->use_role;
1039
1040         /* Set the role if requested */
1041         if (use_role && AH->remoteVersion >= 80100)
1042         {
1043                 PQExpBuffer query = createPQExpBuffer();
1044
1045                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1046                 ExecuteSqlStatement(AH, query->data);
1047                 destroyPQExpBuffer(query);
1048
1049                 /* save it for possible later use by parallel workers */
1050                 if (!AH->use_role)
1051                         AH->use_role = pg_strdup(use_role);
1052         }
1053
1054         /* Set the datestyle to ISO to ensure the dump's portability */
1055         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1056
1057         /* Likewise, avoid using sql_standard intervalstyle */
1058         if (AH->remoteVersion >= 80400)
1059                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1060
1061         /*
1062          * Set extra_float_digits so that we can dump float data exactly (given
1063          * correctly implemented float I/O code, anyway)
1064          */
1065         if (AH->remoteVersion >= 90000)
1066                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1067         else
1068                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1069
1070         /*
1071          * If synchronized scanning is supported, disable it, to prevent
1072          * unpredictable changes in row ordering across a dump and reload.
1073          */
1074         if (AH->remoteVersion >= 80300)
1075                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1076
1077         /*
1078          * Disable timeouts if supported.
1079          */
1080         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1081         if (AH->remoteVersion >= 90300)
1082                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1083         if (AH->remoteVersion >= 90600)
1084                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1085
1086         /*
1087          * Quote all identifiers, if requested.
1088          */
1089         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1090                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1091
1092         /*
1093          * Adjust row-security mode, if supported.
1094          */
1095         if (AH->remoteVersion >= 90500)
1096         {
1097                 if (dopt->enable_row_security)
1098                         ExecuteSqlStatement(AH, "SET row_security = on");
1099                 else
1100                         ExecuteSqlStatement(AH, "SET row_security = off");
1101         }
1102
1103         /*
1104          * Start transaction-snapshot mode transaction to dump consistent data.
1105          */
1106         ExecuteSqlStatement(AH, "BEGIN");
1107         if (AH->remoteVersion >= 90100)
1108         {
1109                 /*
1110                  * To support the combination of serializable_deferrable with the jobs
1111                  * option we use REPEATABLE READ for the worker connections that are
1112                  * passed a snapshot.  As long as the snapshot is acquired in a
1113                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1114                  * REPEATABLE READ transaction provides the appropriate integrity
1115                  * guarantees.  This is a kluge, but safe for back-patching.
1116                  */
1117                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1118                         ExecuteSqlStatement(AH,
1119                                                                 "SET TRANSACTION ISOLATION LEVEL "
1120                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1121                 else
1122                         ExecuteSqlStatement(AH,
1123                                                                 "SET TRANSACTION ISOLATION LEVEL "
1124                                                                 "REPEATABLE READ, READ ONLY");
1125         }
1126         else
1127         {
1128                 ExecuteSqlStatement(AH,
1129                                                         "SET TRANSACTION ISOLATION LEVEL "
1130                                                         "SERIALIZABLE, READ ONLY");
1131         }
1132
1133         /*
1134          * If user specified a snapshot to use, select that.  In a parallel dump
1135          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1136          * is already set (if the server can handle it) and we should use that.
1137          */
1138         if (dumpsnapshot)
1139                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1140
1141         if (AH->sync_snapshot_id)
1142         {
1143                 PQExpBuffer query = createPQExpBuffer();
1144
1145                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1146                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1147                 ExecuteSqlStatement(AH, query->data);
1148                 destroyPQExpBuffer(query);
1149         }
1150         else if (AH->numWorkers > 1 &&
1151                          AH->remoteVersion >= 90200 &&
1152                          !dopt->no_synchronized_snapshots)
1153         {
1154                 if (AH->isStandby && AH->remoteVersion < 100000)
1155                         exit_horribly(NULL,
1156                                                   "Synchronized snapshots on standby servers are not supported by this server version.\n"
1157                                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1158                                                   "synchronized snapshots.\n");
1159
1160
1161                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1162         }
1163 }
1164
1165 /* Set up connection for a parallel worker process */
1166 static void
1167 setupDumpWorker(Archive *AH)
1168 {
1169         /*
1170          * We want to re-select all the same values the master connection is
1171          * using.  We'll have inherited directly-usable values in
1172          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1173          * inherited encoding value back to a string to pass to setup_connection.
1174          */
1175         setup_connection(AH,
1176                                          pg_encoding_to_char(AH->encoding),
1177                                          NULL,
1178                                          NULL);
1179 }
1180
1181 static char *
1182 get_synchronized_snapshot(Archive *fout)
1183 {
1184         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1185         char       *result;
1186         PGresult   *res;
1187
1188         res = ExecuteSqlQueryForSingleRow(fout, query);
1189         result = pg_strdup(PQgetvalue(res, 0, 0));
1190         PQclear(res);
1191
1192         return result;
1193 }
1194
1195 static ArchiveFormat
1196 parseArchiveFormat(const char *format, ArchiveMode *mode)
1197 {
1198         ArchiveFormat archiveFormat;
1199
1200         *mode = archModeWrite;
1201
1202         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1203         {
1204                 /* This is used by pg_dumpall, and is not documented */
1205                 archiveFormat = archNull;
1206                 *mode = archModeAppend;
1207         }
1208         else if (pg_strcasecmp(format, "c") == 0)
1209                 archiveFormat = archCustom;
1210         else if (pg_strcasecmp(format, "custom") == 0)
1211                 archiveFormat = archCustom;
1212         else if (pg_strcasecmp(format, "d") == 0)
1213                 archiveFormat = archDirectory;
1214         else if (pg_strcasecmp(format, "directory") == 0)
1215                 archiveFormat = archDirectory;
1216         else if (pg_strcasecmp(format, "p") == 0)
1217                 archiveFormat = archNull;
1218         else if (pg_strcasecmp(format, "plain") == 0)
1219                 archiveFormat = archNull;
1220         else if (pg_strcasecmp(format, "t") == 0)
1221                 archiveFormat = archTar;
1222         else if (pg_strcasecmp(format, "tar") == 0)
1223                 archiveFormat = archTar;
1224         else
1225                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1226         return archiveFormat;
1227 }
1228
1229 /*
1230  * Find the OIDs of all schemas matching the given list of patterns,
1231  * and append them to the given OID list.
1232  */
1233 static void
1234 expand_schema_name_patterns(Archive *fout,
1235                                                         SimpleStringList *patterns,
1236                                                         SimpleOidList *oids,
1237                                                         bool strict_names)
1238 {
1239         PQExpBuffer query;
1240         PGresult   *res;
1241         SimpleStringListCell *cell;
1242         int                     i;
1243
1244         if (patterns->head == NULL)
1245                 return;                                 /* nothing to do */
1246
1247         query = createPQExpBuffer();
1248
1249         /*
1250          * The loop below runs multiple SELECTs might sometimes result in
1251          * duplicate entries in the OID list, but we don't care.
1252          */
1253
1254         for (cell = patterns->head; cell; cell = cell->next)
1255         {
1256                 appendPQExpBuffer(query,
1257                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1258                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1259                                                           false, NULL, "n.nspname", NULL, NULL);
1260
1261                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1262                 if (strict_names && PQntuples(res) == 0)
1263                         exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1264
1265                 for (i = 0; i < PQntuples(res); i++)
1266                 {
1267                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1268                 }
1269
1270                 PQclear(res);
1271                 resetPQExpBuffer(query);
1272         }
1273
1274         destroyPQExpBuffer(query);
1275 }
1276
1277 /*
1278  * Find the OIDs of all tables matching the given list of patterns,
1279  * and append them to the given OID list.
1280  */
1281 static void
1282 expand_table_name_patterns(Archive *fout,
1283                                                    SimpleStringList *patterns, SimpleOidList *oids,
1284                                                    bool strict_names)
1285 {
1286         PQExpBuffer query;
1287         PGresult   *res;
1288         SimpleStringListCell *cell;
1289         int                     i;
1290
1291         if (patterns->head == NULL)
1292                 return;                                 /* nothing to do */
1293
1294         query = createPQExpBuffer();
1295
1296         /*
1297          * this might sometimes result in duplicate entries in the OID list, but
1298          * we don't care.
1299          */
1300
1301         for (cell = patterns->head; cell; cell = cell->next)
1302         {
1303                 /*
1304                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1305                  * would be unnecessary given a pg_table_is_visible() variant taking a
1306                  * search_path argument.
1307                  */
1308                 appendPQExpBuffer(query,
1309                                                   "SELECT c.oid"
1310                                                   "\nFROM pg_catalog.pg_class c"
1311                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1312                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1313                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1314                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1315                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1316                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1317                                                   RELKIND_PARTITIONED_TABLE);
1318                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1319                                                           false, "n.nspname", "c.relname", NULL,
1320                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1321
1322                 ExecuteSqlStatement(fout, "RESET search_path");
1323                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1324                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1325                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1326                 if (strict_names && PQntuples(res) == 0)
1327                         exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1328
1329                 for (i = 0; i < PQntuples(res); i++)
1330                 {
1331                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1332                 }
1333
1334                 PQclear(res);
1335                 resetPQExpBuffer(query);
1336         }
1337
1338         destroyPQExpBuffer(query);
1339 }
1340
1341 /*
1342  * checkExtensionMembership
1343  *              Determine whether object is an extension member, and if so,
1344  *              record an appropriate dependency and set the object's dump flag.
1345  *
1346  * It's important to call this for each object that could be an extension
1347  * member.  Generally, we integrate this with determining the object's
1348  * to-be-dumped-ness, since extension membership overrides other rules for that.
1349  *
1350  * Returns true if object is an extension member, else false.
1351  */
1352 static bool
1353 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1354 {
1355         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1356
1357         if (ext == NULL)
1358                 return false;
1359
1360         dobj->ext_member = true;
1361
1362         /* Record dependency so that getDependencies needn't deal with that */
1363         addObjectDependency(dobj, ext->dobj.dumpId);
1364
1365         /*
1366          * In 9.6 and above, mark the member object to have any non-initial ACL,
1367          * policies, and security labels dumped.
1368          *
1369          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1370          * extract the information about the object.  We don't provide support for
1371          * initial policies and security labels and it seems unlikely for those to
1372          * ever exist, but we may have to revisit this later.
1373          *
1374          * Prior to 9.6, we do not include any extension member components.
1375          *
1376          * In binary upgrades, we still dump all components of the members
1377          * individually, since the idea is to exactly reproduce the database
1378          * contents rather than replace the extension contents with something
1379          * different.
1380          */
1381         if (fout->dopt->binary_upgrade)
1382                 dobj->dump = ext->dobj.dump;
1383         else
1384         {
1385                 if (fout->remoteVersion < 90600)
1386                         dobj->dump = DUMP_COMPONENT_NONE;
1387                 else
1388                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1389                                                                                                         DUMP_COMPONENT_SECLABEL |
1390                                                                                                         DUMP_COMPONENT_POLICY);
1391         }
1392
1393         return true;
1394 }
1395
1396 /*
1397  * selectDumpableNamespace: policy-setting subroutine
1398  *              Mark a namespace as to be dumped or not
1399  */
1400 static void
1401 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1402 {
1403         /*
1404          * If specific tables are being dumped, do not dump any complete
1405          * namespaces. If specific namespaces are being dumped, dump just those
1406          * namespaces. Otherwise, dump all non-system namespaces.
1407          */
1408         if (table_include_oids.head != NULL)
1409                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1410         else if (schema_include_oids.head != NULL)
1411                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1412                         simple_oid_list_member(&schema_include_oids,
1413                                                                    nsinfo->dobj.catId.oid) ?
1414                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1415         else if (fout->remoteVersion >= 90600 &&
1416                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1417         {
1418                 /*
1419                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1420                  * they are interesting (and not the original ACLs which were set at
1421                  * initdb time, see pg_init_privs).
1422                  */
1423                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1424         }
1425         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1426                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1427         {
1428                 /* Other system schemas don't get dumped */
1429                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1430         }
1431         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1432         {
1433                 /*
1434                  * The public schema is a strange beast that sits in a sort of
1435                  * no-mans-land between being a system object and a user object.  We
1436                  * don't want to dump creation or comment commands for it, because
1437                  * that complicates matters for non-superuser use of pg_dump.  But we
1438                  * should dump any ACL changes that have occurred for it, and of
1439                  * course we should dump contained objects.
1440                  */
1441                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1442                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1443         }
1444         else
1445                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1446
1447         /*
1448          * In any case, a namespace can be excluded by an exclusion switch
1449          */
1450         if (nsinfo->dobj.dump_contains &&
1451                 simple_oid_list_member(&schema_exclude_oids,
1452                                                            nsinfo->dobj.catId.oid))
1453                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1454
1455         /*
1456          * If the schema belongs to an extension, allow extension membership to
1457          * override the dump decision for the schema itself.  However, this does
1458          * not change dump_contains, so this won't change what we do with objects
1459          * within the schema.  (If they belong to the extension, they'll get
1460          * suppressed by it, otherwise not.)
1461          */
1462         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1463 }
1464
1465 /*
1466  * selectDumpableTable: policy-setting subroutine
1467  *              Mark a table as to be dumped or not
1468  */
1469 static void
1470 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1471 {
1472         if (checkExtensionMembership(&tbinfo->dobj, fout))
1473                 return;                                 /* extension membership overrides all else */
1474
1475         /*
1476          * If specific tables are being dumped, dump just those tables; else, dump
1477          * according to the parent namespace's dump flag.
1478          */
1479         if (table_include_oids.head != NULL)
1480                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1481                                                                                                    tbinfo->dobj.catId.oid) ?
1482                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1483         else
1484                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1485
1486         /*
1487          * In any case, a table can be excluded by an exclusion switch
1488          */
1489         if (tbinfo->dobj.dump &&
1490                 simple_oid_list_member(&table_exclude_oids,
1491                                                            tbinfo->dobj.catId.oid))
1492                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1493 }
1494
1495 /*
1496  * selectDumpableType: policy-setting subroutine
1497  *              Mark a type as to be dumped or not
1498  *
1499  * If it's a table's rowtype or an autogenerated array type, we also apply a
1500  * special type code to facilitate sorting into the desired order.  (We don't
1501  * want to consider those to be ordinary types because that would bring tables
1502  * up into the datatype part of the dump order.)  We still set the object's
1503  * dump flag; that's not going to cause the dummy type to be dumped, but we
1504  * need it so that casts involving such types will be dumped correctly -- see
1505  * dumpCast.  This means the flag should be set the same as for the underlying
1506  * object (the table or base type).
1507  */
1508 static void
1509 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1510 {
1511         /* skip complex types, except for standalone composite types */
1512         if (OidIsValid(tyinfo->typrelid) &&
1513                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1514         {
1515                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1516
1517                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1518                 if (tytable != NULL)
1519                         tyinfo->dobj.dump = tytable->dobj.dump;
1520                 else
1521                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1522                 return;
1523         }
1524
1525         /* skip auto-generated array types */
1526         if (tyinfo->isArray)
1527         {
1528                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1529
1530                 /*
1531                  * Fall through to set the dump flag; we assume that the subsequent
1532                  * rules will do the same thing as they would for the array's base
1533                  * type.  (We cannot reliably look up the base type here, since
1534                  * getTypes may not have processed it yet.)
1535                  */
1536         }
1537
1538         if (checkExtensionMembership(&tyinfo->dobj, fout))
1539                 return;                                 /* extension membership overrides all else */
1540
1541         /* Dump based on if the contents of the namespace are being dumped */
1542         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1543 }
1544
1545 /*
1546  * selectDumpableDefaultACL: policy-setting subroutine
1547  *              Mark a default ACL as to be dumped or not
1548  *
1549  * For per-schema default ACLs, dump if the schema is to be dumped.
1550  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1551  * and aclsSkip are checked separately.
1552  */
1553 static void
1554 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1555 {
1556         /* Default ACLs can't be extension members */
1557
1558         if (dinfo->dobj.namespace)
1559                 /* default ACLs are considered part of the namespace */
1560                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1561         else
1562                 dinfo->dobj.dump = dopt->include_everything ?
1563                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1564 }
1565
1566 /*
1567  * selectDumpableCast: policy-setting subroutine
1568  *              Mark a cast as to be dumped or not
1569  *
1570  * Casts do not belong to any particular namespace (since they haven't got
1571  * names), nor do they have identifiable owners.  To distinguish user-defined
1572  * casts from built-in ones, we must resort to checking whether the cast's
1573  * OID is in the range reserved for initdb.
1574  */
1575 static void
1576 selectDumpableCast(CastInfo *cast, Archive *fout)
1577 {
1578         if (checkExtensionMembership(&cast->dobj, fout))
1579                 return;                                 /* extension membership overrides all else */
1580
1581         /*
1582          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1583          * support ACLs currently.
1584          */
1585         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1586                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1587         else
1588                 cast->dobj.dump = fout->dopt->include_everything ?
1589                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1590 }
1591
1592 /*
1593  * selectDumpableProcLang: policy-setting subroutine
1594  *              Mark a procedural language as to be dumped or not
1595  *
1596  * Procedural languages do not belong to any particular namespace.  To
1597  * identify built-in languages, we must resort to checking whether the
1598  * language's OID is in the range reserved for initdb.
1599  */
1600 static void
1601 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1602 {
1603         if (checkExtensionMembership(&plang->dobj, fout))
1604                 return;                                 /* extension membership overrides all else */
1605
1606         /*
1607          * Only include procedural languages when we are dumping everything.
1608          *
1609          * For from-initdb procedural languages, only include ACLs, as we do for
1610          * the pg_catalog namespace.  We need this because procedural languages do
1611          * not live in any namespace.
1612          */
1613         if (!fout->dopt->include_everything)
1614                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1615         else
1616         {
1617                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1618                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1619                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1620                 else
1621                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1622         }
1623 }
1624
1625 /*
1626  * selectDumpableAccessMethod: policy-setting subroutine
1627  *              Mark an access method as to be dumped or not
1628  *
1629  * Access methods do not belong to any particular namespace.  To identify
1630  * built-in access methods, we must resort to checking whether the
1631  * method's OID is in the range reserved for initdb.
1632  */
1633 static void
1634 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1635 {
1636         if (checkExtensionMembership(&method->dobj, fout))
1637                 return;                                 /* extension membership overrides all else */
1638
1639         /*
1640          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1641          * they do not support ACLs currently.
1642          */
1643         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1644                 method->dobj.dump = DUMP_COMPONENT_NONE;
1645         else
1646                 method->dobj.dump = fout->dopt->include_everything ?
1647                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1648 }
1649
1650 /*
1651  * selectDumpableExtension: policy-setting subroutine
1652  *              Mark an extension as to be dumped or not
1653  *
1654  * Built-in extensions should be skipped except for checking ACLs, since we
1655  * assume those will already be installed in the target database.  We identify
1656  * such extensions by their having OIDs in the range reserved for initdb.
1657  * We dump all user-added extensions by default, or none of them if
1658  * include_everything is false (i.e., a --schema or --table switch was given).
1659  */
1660 static void
1661 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1662 {
1663         /*
1664          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1665          * change permissions on their member objects, if they wish to, and have
1666          * those changes preserved.
1667          */
1668         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1669                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1670         else
1671                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1672                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1673                         DUMP_COMPONENT_NONE;
1674 }
1675
1676 /*
1677  * selectDumpablePublicationTable: policy-setting subroutine
1678  *              Mark a publication table as to be dumped or not
1679  *
1680  * Publication tables have schemas, but those are ignored in decision making,
1681  * because publications are only dumped when we are dumping everything.
1682  */
1683 static void
1684 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1685 {
1686         if (checkExtensionMembership(dobj, fout))
1687                 return;                                 /* extension membership overrides all else */
1688
1689         dobj->dump = fout->dopt->include_everything ?
1690                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1691 }
1692
1693 /*
1694  * selectDumpableObject: policy-setting subroutine
1695  *              Mark a generic dumpable object as to be dumped or not
1696  *
1697  * Use this only for object types without a special-case routine above.
1698  */
1699 static void
1700 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1701 {
1702         if (checkExtensionMembership(dobj, fout))
1703                 return;                                 /* extension membership overrides all else */
1704
1705         /*
1706          * Default policy is to dump if parent namespace is dumpable, or for
1707          * non-namespace-associated items, dump if we're dumping "everything".
1708          */
1709         if (dobj->namespace)
1710                 dobj->dump = dobj->namespace->dobj.dump_contains;
1711         else
1712                 dobj->dump = fout->dopt->include_everything ?
1713                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1714 }
1715
1716 /*
1717  *      Dump a table's contents for loading using the COPY command
1718  *      - this routine is called by the Archiver when it wants the table
1719  *        to be dumped.
1720  */
1721
1722 static int
1723 dumpTableData_copy(Archive *fout, void *dcontext)
1724 {
1725         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1726         TableInfo  *tbinfo = tdinfo->tdtable;
1727         const char *classname = tbinfo->dobj.name;
1728         PQExpBuffer q = createPQExpBuffer();
1729
1730         /*
1731          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1732          * which uses it already.
1733          */
1734         PQExpBuffer clistBuf = createPQExpBuffer();
1735         PGconn     *conn = GetConnection(fout);
1736         PGresult   *res;
1737         int                     ret;
1738         char       *copybuf;
1739         const char *column_list;
1740
1741         if (g_verbose)
1742                 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1743                                   tbinfo->dobj.namespace->dobj.name, classname);
1744
1745         /*
1746          * Specify the column list explicitly so that we have no possibility of
1747          * retrieving data in the wrong column order.  (The default column
1748          * ordering of COPY will not be what we want in certain corner cases
1749          * involving ADD COLUMN and inheritance.)
1750          */
1751         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1752
1753         if (tdinfo->filtercond)
1754         {
1755                 /* Note: this syntax is only supported in 8.2 and up */
1756                 appendPQExpBufferStr(q, "COPY (SELECT ");
1757                 /* klugery to get rid of parens in column list */
1758                 if (strlen(column_list) > 2)
1759                 {
1760                         appendPQExpBufferStr(q, column_list + 1);
1761                         q->data[q->len - 1] = ' ';
1762                 }
1763                 else
1764                         appendPQExpBufferStr(q, "* ");
1765                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1766                                                   fmtQualifiedDumpable(tbinfo),
1767                                                   tdinfo->filtercond);
1768         }
1769         else
1770         {
1771                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1772                                                   fmtQualifiedDumpable(tbinfo),
1773                                                   column_list);
1774         }
1775         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1776         PQclear(res);
1777         destroyPQExpBuffer(clistBuf);
1778
1779         for (;;)
1780         {
1781                 ret = PQgetCopyData(conn, &copybuf, 0);
1782
1783                 if (ret < 0)
1784                         break;                          /* done or error */
1785
1786                 if (copybuf)
1787                 {
1788                         WriteData(fout, copybuf, ret);
1789                         PQfreemem(copybuf);
1790                 }
1791
1792                 /* ----------
1793                  * THROTTLE:
1794                  *
1795                  * There was considerable discussion in late July, 2000 regarding
1796                  * slowing down pg_dump when backing up large tables. Users with both
1797                  * slow & fast (multi-processor) machines experienced performance
1798                  * degradation when doing a backup.
1799                  *
1800                  * Initial attempts based on sleeping for a number of ms for each ms
1801                  * of work were deemed too complex, then a simple 'sleep in each loop'
1802                  * implementation was suggested. The latter failed because the loop
1803                  * was too tight. Finally, the following was implemented:
1804                  *
1805                  * If throttle is non-zero, then
1806                  *              See how long since the last sleep.
1807                  *              Work out how long to sleep (based on ratio).
1808                  *              If sleep is more than 100ms, then
1809                  *                      sleep
1810                  *                      reset timer
1811                  *              EndIf
1812                  * EndIf
1813                  *
1814                  * where the throttle value was the number of ms to sleep per ms of
1815                  * work. The calculation was done in each loop.
1816                  *
1817                  * Most of the hard work is done in the backend, and this solution
1818                  * still did not work particularly well: on slow machines, the ratio
1819                  * was 50:1, and on medium paced machines, 1:1, and on fast
1820                  * multi-processor machines, it had little or no effect, for reasons
1821                  * that were unclear.
1822                  *
1823                  * Further discussion ensued, and the proposal was dropped.
1824                  *
1825                  * For those people who want this feature, it can be implemented using
1826                  * gettimeofday in each loop, calculating the time since last sleep,
1827                  * multiplying that by the sleep ratio, then if the result is more
1828                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1829                  * function to sleep for a subsecond period ie.
1830                  *
1831                  * select(0, NULL, NULL, NULL, &tvi);
1832                  *
1833                  * This will return after the interval specified in the structure tvi.
1834                  * Finally, call gettimeofday again to save the 'last sleep time'.
1835                  * ----------
1836                  */
1837         }
1838         archprintf(fout, "\\.\n\n\n");
1839
1840         if (ret == -2)
1841         {
1842                 /* copy data transfer failed */
1843                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1844                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1845                 write_msg(NULL, "The command was: %s\n", q->data);
1846                 exit_nicely(1);
1847         }
1848
1849         /* Check command status and return to normal libpq state */
1850         res = PQgetResult(conn);
1851         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1852         {
1853                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1854                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1855                 write_msg(NULL, "The command was: %s\n", q->data);
1856                 exit_nicely(1);
1857         }
1858         PQclear(res);
1859
1860         /* Do this to ensure we've pumped libpq back to idle state */
1861         if (PQgetResult(conn) != NULL)
1862                 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1863                                   classname);
1864
1865         destroyPQExpBuffer(q);
1866         return 1;
1867 }
1868
1869 /*
1870  * Dump table data using INSERT commands.
1871  *
1872  * Caution: when we restore from an archive file direct to database, the
1873  * INSERT commands emitted by this function have to be parsed by
1874  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1875  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1876  */
1877 static int
1878 dumpTableData_insert(Archive *fout, void *dcontext)
1879 {
1880         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1881         TableInfo  *tbinfo = tdinfo->tdtable;
1882         DumpOptions *dopt = fout->dopt;
1883         PQExpBuffer q = createPQExpBuffer();
1884         PQExpBuffer insertStmt = NULL;
1885         PGresult   *res;
1886         int                     tuple;
1887         int                     nfields;
1888         int                     field;
1889
1890         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1891                                           "SELECT * FROM ONLY %s",
1892                                           fmtQualifiedDumpable(tbinfo));
1893         if (tdinfo->filtercond)
1894                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1895
1896         ExecuteSqlStatement(fout, q->data);
1897
1898         while (1)
1899         {
1900                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1901                                                           PGRES_TUPLES_OK);
1902                 nfields = PQnfields(res);
1903                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1904                 {
1905                         /*
1906                          * First time through, we build as much of the INSERT statement as
1907                          * possible in "insertStmt", which we can then just print for each
1908                          * line. If the table happens to have zero columns then this will
1909                          * be a complete statement, otherwise it will end in "VALUES(" and
1910                          * be ready to have the row's column values appended.
1911                          */
1912                         if (insertStmt == NULL)
1913                         {
1914                                 TableInfo  *targettab;
1915
1916                                 insertStmt = createPQExpBuffer();
1917
1918                                 /*
1919                                  * When load-via-partition-root is set, get the root table
1920                                  * name for the partition table, so that we can reload data
1921                                  * through the root table.
1922                                  */
1923                                 if (dopt->load_via_partition_root && tbinfo->ispartition)
1924                                         targettab = getRootTableInfo(tbinfo);
1925                                 else
1926                                         targettab = tbinfo;
1927
1928                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1929                                                                   fmtQualifiedDumpable(targettab));
1930
1931                                 /* corner case for zero-column table */
1932                                 if (nfields == 0)
1933                                 {
1934                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1935                                 }
1936                                 else
1937                                 {
1938                                         /* append the list of column names if required */
1939                                         if (dopt->column_inserts)
1940                                         {
1941                                                 appendPQExpBufferChar(insertStmt, '(');
1942                                                 for (field = 0; field < nfields; field++)
1943                                                 {
1944                                                         if (field > 0)
1945                                                                 appendPQExpBufferStr(insertStmt, ", ");
1946                                                         appendPQExpBufferStr(insertStmt,
1947                                                                                                  fmtId(PQfname(res, field)));
1948                                                 }
1949                                                 appendPQExpBufferStr(insertStmt, ") ");
1950                                         }
1951
1952                                         if (tbinfo->needs_override)
1953                                                 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1954
1955                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1956                                 }
1957                         }
1958
1959                         archputs(insertStmt->data, fout);
1960
1961                         /* if it is zero-column table then we're done */
1962                         if (nfields == 0)
1963                                 continue;
1964
1965                         for (field = 0; field < nfields; field++)
1966                         {
1967                                 if (field > 0)
1968                                         archputs(", ", fout);
1969                                 if (PQgetisnull(res, tuple, field))
1970                                 {
1971                                         archputs("NULL", fout);
1972                                         continue;
1973                                 }
1974
1975                                 /* XXX This code is partially duplicated in ruleutils.c */
1976                                 switch (PQftype(res, field))
1977                                 {
1978                                         case INT2OID:
1979                                         case INT4OID:
1980                                         case INT8OID:
1981                                         case OIDOID:
1982                                         case FLOAT4OID:
1983                                         case FLOAT8OID:
1984                                         case NUMERICOID:
1985                                                 {
1986                                                         /*
1987                                                          * These types are printed without quotes unless
1988                                                          * they contain values that aren't accepted by the
1989                                                          * scanner unquoted (e.g., 'NaN').  Note that
1990                                                          * strtod() and friends might accept NaN, so we
1991                                                          * can't use that to test.
1992                                                          *
1993                                                          * In reality we only need to defend against
1994                                                          * infinity and NaN, so we need not get too crazy
1995                                                          * about pattern matching here.
1996                                                          */
1997                                                         const char *s = PQgetvalue(res, tuple, field);
1998
1999                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2000                                                                 archputs(s, fout);
2001                                                         else
2002                                                                 archprintf(fout, "'%s'", s);
2003                                                 }
2004                                                 break;
2005
2006                                         case BITOID:
2007                                         case VARBITOID:
2008                                                 archprintf(fout, "B'%s'",
2009                                                                    PQgetvalue(res, tuple, field));
2010                                                 break;
2011
2012                                         case BOOLOID:
2013                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2014                                                         archputs("true", fout);
2015                                                 else
2016                                                         archputs("false", fout);
2017                                                 break;
2018
2019                                         default:
2020                                                 /* All other types are printed as string literals. */
2021                                                 resetPQExpBuffer(q);
2022                                                 appendStringLiteralAH(q,
2023                                                                                           PQgetvalue(res, tuple, field),
2024                                                                                           fout);
2025                                                 archputs(q->data, fout);
2026                                                 break;
2027                                 }
2028                         }
2029
2030                         if (!dopt->do_nothing)
2031                                 archputs(");\n", fout);
2032                         else
2033                                 archputs(") ON CONFLICT DO NOTHING;\n", fout);
2034                 }
2035
2036                 if (PQntuples(res) <= 0)
2037                 {
2038                         PQclear(res);
2039                         break;
2040                 }
2041                 PQclear(res);
2042         }
2043
2044         archputs("\n\n", fout);
2045
2046         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2047
2048         destroyPQExpBuffer(q);
2049         if (insertStmt != NULL)
2050                 destroyPQExpBuffer(insertStmt);
2051
2052         return 1;
2053 }
2054
2055 /*
2056  * getRootTableInfo:
2057  *     get the root TableInfo for the given partition table.
2058  */
2059 static TableInfo *
2060 getRootTableInfo(TableInfo *tbinfo)
2061 {
2062         TableInfo  *parentTbinfo;
2063
2064         Assert(tbinfo->ispartition);
2065         Assert(tbinfo->numParents == 1);
2066
2067         parentTbinfo = tbinfo->parents[0];
2068         while (parentTbinfo->ispartition)
2069         {
2070                 Assert(parentTbinfo->numParents == 1);
2071                 parentTbinfo = parentTbinfo->parents[0];
2072         }
2073
2074         return parentTbinfo;
2075 }
2076
2077 /*
2078  * dumpTableData -
2079  *        dump the contents of a single table
2080  *
2081  * Actually, this just makes an ArchiveEntry for the table contents.
2082  */
2083 static void
2084 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2085 {
2086         DumpOptions *dopt = fout->dopt;
2087         TableInfo  *tbinfo = tdinfo->tdtable;
2088         PQExpBuffer copyBuf = createPQExpBuffer();
2089         PQExpBuffer clistBuf = createPQExpBuffer();
2090         DataDumperPtr dumpFn;
2091         char       *copyStmt;
2092         const char *copyFrom;
2093
2094         if (!dopt->dump_inserts)
2095         {
2096                 /* Dump/restore using COPY */
2097                 dumpFn = dumpTableData_copy;
2098
2099                 /*
2100                  * When load-via-partition-root is set, get the root table name for
2101                  * the partition table, so that we can reload data through the root
2102                  * table.
2103                  */
2104                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2105                 {
2106                         TableInfo  *parentTbinfo;
2107
2108                         parentTbinfo = getRootTableInfo(tbinfo);
2109                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2110                 }
2111                 else
2112                         copyFrom = fmtQualifiedDumpable(tbinfo);
2113
2114                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2115                 appendPQExpBuffer(copyBuf, "COPY %s ",
2116                                                   copyFrom);
2117                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2118                                                   fmtCopyColumnList(tbinfo, clistBuf));
2119                 copyStmt = copyBuf->data;
2120         }
2121         else
2122         {
2123                 /* Restore using INSERT */
2124                 dumpFn = dumpTableData_insert;
2125                 copyStmt = NULL;
2126         }
2127
2128         /*
2129          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2130          * dependency on its table as "special" and pass it to ArchiveEntry now.
2131          * See comments for BuildArchiveDependencies.
2132          */
2133         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2134         {
2135                 TocEntry   *te;
2136
2137                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2138                                                   tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2139                                                   NULL, tbinfo->rolname,
2140                                                   "TABLE DATA", SECTION_DATA,
2141                                                   "", "", copyStmt,
2142                                                   &(tbinfo->dobj.dumpId), 1,
2143                                                   dumpFn, tdinfo);
2144
2145                 /*
2146                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2147                  * and want to order dump jobs by table size.  We choose to measure
2148                  * dataLength in table pages during dump, so no scaling is needed.
2149                  * However, relpages is declared as "integer" in pg_class, and hence
2150                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2151                  * Cast so that we get the right interpretation of table sizes
2152                  * exceeding INT_MAX pages.
2153                  */
2154                 te->dataLength = (BlockNumber) tbinfo->relpages;
2155         }
2156
2157         destroyPQExpBuffer(copyBuf);
2158         destroyPQExpBuffer(clistBuf);
2159 }
2160
2161 /*
2162  * refreshMatViewData -
2163  *        load or refresh the contents of a single materialized view
2164  *
2165  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2166  * statement.
2167  */
2168 static void
2169 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2170 {
2171         TableInfo  *tbinfo = tdinfo->tdtable;
2172         PQExpBuffer q;
2173
2174         /* If the materialized view is not flagged as populated, skip this. */
2175         if (!tbinfo->relispopulated)
2176                 return;
2177
2178         q = createPQExpBuffer();
2179
2180         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2181                                           fmtQualifiedDumpable(tbinfo));
2182
2183         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2184                 ArchiveEntry(fout,
2185                                          tdinfo->dobj.catId,    /* catalog ID */
2186                                          tdinfo->dobj.dumpId,   /* dump ID */
2187                                          tbinfo->dobj.name, /* Name */
2188                                          tbinfo->dobj.namespace->dobj.name, /* Namespace */
2189                                          NULL,          /* Tablespace */
2190                                          tbinfo->rolname,       /* Owner */
2191                                          "MATERIALIZED VIEW DATA",      /* Desc */
2192                                          SECTION_POST_DATA, /* Section */
2193                                          q->data,       /* Create */
2194                                          "",            /* Del */
2195                                          NULL,          /* Copy */
2196                                          tdinfo->dobj.dependencies, /* Deps */
2197                                          tdinfo->dobj.nDeps,    /* # Deps */
2198                                          NULL,          /* Dumper */
2199                                          NULL);         /* Dumper Arg */
2200
2201         destroyPQExpBuffer(q);
2202 }
2203
2204 /*
2205  * getTableData -
2206  *        set up dumpable objects representing the contents of tables
2207  */
2208 static void
2209 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2210 {
2211         int                     i;
2212
2213         for (i = 0; i < numTables; i++)
2214         {
2215                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2216                         (!relkind || tblinfo[i].relkind == relkind))
2217                         makeTableDataInfo(dopt, &(tblinfo[i]));
2218         }
2219 }
2220
2221 /*
2222  * Make a dumpable object for the data of this specific table
2223  *
2224  * Note: we make a TableDataInfo if and only if we are going to dump the
2225  * table data; the "dump" flag in such objects isn't used.
2226  */
2227 static void
2228 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2229 {
2230         TableDataInfo *tdinfo;
2231
2232         /*
2233          * Nothing to do if we already decided to dump the table.  This will
2234          * happen for "config" tables.
2235          */
2236         if (tbinfo->dataObj != NULL)
2237                 return;
2238
2239         /* Skip VIEWs (no data to dump) */
2240         if (tbinfo->relkind == RELKIND_VIEW)
2241                 return;
2242         /* Skip FOREIGN TABLEs (no data to dump) */
2243         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2244                 return;
2245         /* Skip partitioned tables (data in partitions) */
2246         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2247                 return;
2248
2249         /* Don't dump data in unlogged tables, if so requested */
2250         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2251                 dopt->no_unlogged_table_data)
2252                 return;
2253
2254         /* Check that the data is not explicitly excluded */
2255         if (simple_oid_list_member(&tabledata_exclude_oids,
2256                                                            tbinfo->dobj.catId.oid))
2257                 return;
2258
2259         /* OK, let's dump it */
2260         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2261
2262         if (tbinfo->relkind == RELKIND_MATVIEW)
2263                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2264         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2265                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2266         else
2267                 tdinfo->dobj.objType = DO_TABLE_DATA;
2268
2269         /*
2270          * Note: use tableoid 0 so that this object won't be mistaken for
2271          * something that pg_depend entries apply to.
2272          */
2273         tdinfo->dobj.catId.tableoid = 0;
2274         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2275         AssignDumpId(&tdinfo->dobj);
2276         tdinfo->dobj.name = tbinfo->dobj.name;
2277         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2278         tdinfo->tdtable = tbinfo;
2279         tdinfo->filtercond = NULL;      /* might get set later */
2280         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2281
2282         tbinfo->dataObj = tdinfo;
2283 }
2284
2285 /*
2286  * The refresh for a materialized view must be dependent on the refresh for
2287  * any materialized view that this one is dependent on.
2288  *
2289  * This must be called after all the objects are created, but before they are
2290  * sorted.
2291  */
2292 static void
2293 buildMatViewRefreshDependencies(Archive *fout)
2294 {
2295         PQExpBuffer query;
2296         PGresult   *res;
2297         int                     ntups,
2298                                 i;
2299         int                     i_classid,
2300                                 i_objid,
2301                                 i_refobjid;
2302
2303         /* No Mat Views before 9.3. */
2304         if (fout->remoteVersion < 90300)
2305                 return;
2306
2307         query = createPQExpBuffer();
2308
2309         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2310                                                  "( "
2311                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2312                                                  "FROM pg_depend d1 "
2313                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2314                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2315                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2316                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2317                                                  "AND d2.objid = r1.oid "
2318                                                  "AND d2.refobjid <> d1.objid "
2319                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2320                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2321                                                  CppAsString2(RELKIND_VIEW) ") "
2322                                                  "WHERE d1.classid = 'pg_class'::regclass "
2323                                                  "UNION "
2324                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2325                                                  "FROM w "
2326                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2327                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2328                                                  "AND d3.objid = r3.oid "
2329                                                  "AND d3.refobjid <> w.refobjid "
2330                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2331                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2332                                                  CppAsString2(RELKIND_VIEW) ") "
2333                                                  ") "
2334                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2335                                                  "FROM w "
2336                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2337
2338         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2339
2340         ntups = PQntuples(res);
2341
2342         i_classid = PQfnumber(res, "classid");
2343         i_objid = PQfnumber(res, "objid");
2344         i_refobjid = PQfnumber(res, "refobjid");
2345
2346         for (i = 0; i < ntups; i++)
2347         {
2348                 CatalogId       objId;
2349                 CatalogId       refobjId;
2350                 DumpableObject *dobj;
2351                 DumpableObject *refdobj;
2352                 TableInfo  *tbinfo;
2353                 TableInfo  *reftbinfo;
2354
2355                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2356                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2357                 refobjId.tableoid = objId.tableoid;
2358                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2359
2360                 dobj = findObjectByCatalogId(objId);
2361                 if (dobj == NULL)
2362                         continue;
2363
2364                 Assert(dobj->objType == DO_TABLE);
2365                 tbinfo = (TableInfo *) dobj;
2366                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2367                 dobj = (DumpableObject *) tbinfo->dataObj;
2368                 if (dobj == NULL)
2369                         continue;
2370                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2371
2372                 refdobj = findObjectByCatalogId(refobjId);
2373                 if (refdobj == NULL)
2374                         continue;
2375
2376                 Assert(refdobj->objType == DO_TABLE);
2377                 reftbinfo = (TableInfo *) refdobj;
2378                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2379                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2380                 if (refdobj == NULL)
2381                         continue;
2382                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2383
2384                 addObjectDependency(dobj, refdobj->dumpId);
2385
2386                 if (!reftbinfo->relispopulated)
2387                         tbinfo->relispopulated = false;
2388         }
2389
2390         PQclear(res);
2391
2392         destroyPQExpBuffer(query);
2393 }
2394
2395 /*
2396  * getTableDataFKConstraints -
2397  *        add dump-order dependencies reflecting foreign key constraints
2398  *
2399  * This code is executed only in a data-only dump --- in schema+data dumps
2400  * we handle foreign key issues by not creating the FK constraints until
2401  * after the data is loaded.  In a data-only dump, however, we want to
2402  * order the table data objects in such a way that a table's referenced
2403  * tables are restored first.  (In the presence of circular references or
2404  * self-references this may be impossible; we'll detect and complain about
2405  * that during the dependency sorting step.)
2406  */
2407 static void
2408 getTableDataFKConstraints(void)
2409 {
2410         DumpableObject **dobjs;
2411         int                     numObjs;
2412         int                     i;
2413
2414         /* Search through all the dumpable objects for FK constraints */
2415         getDumpableObjects(&dobjs, &numObjs);
2416         for (i = 0; i < numObjs; i++)
2417         {
2418                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2419                 {
2420                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2421                         TableInfo  *ftable;
2422
2423                         /* Not interesting unless both tables are to be dumped */
2424                         if (cinfo->contable == NULL ||
2425                                 cinfo->contable->dataObj == NULL)
2426                                 continue;
2427                         ftable = findTableByOid(cinfo->confrelid);
2428                         if (ftable == NULL ||
2429                                 ftable->dataObj == NULL)
2430                                 continue;
2431
2432                         /*
2433                          * Okay, make referencing table's TABLE_DATA object depend on the
2434                          * referenced table's TABLE_DATA object.
2435                          */
2436                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2437                                                                 ftable->dataObj->dobj.dumpId);
2438                 }
2439         }
2440         free(dobjs);
2441 }
2442
2443
2444 /*
2445  * guessConstraintInheritance:
2446  *      In pre-8.4 databases, we can't tell for certain which constraints
2447  *      are inherited.  We assume a CHECK constraint is inherited if its name
2448  *      matches the name of any constraint in the parent.  Originally this code
2449  *      tried to compare the expression texts, but that can fail for various
2450  *      reasons --- for example, if the parent and child tables are in different
2451  *      schemas, reverse-listing of function calls may produce different text
2452  *      (schema-qualified or not) depending on search path.
2453  *
2454  *      In 8.4 and up we can rely on the conislocal field to decide which
2455  *      constraints must be dumped; much safer.
2456  *
2457  *      This function assumes all conislocal flags were initialized to true.
2458  *      It clears the flag on anything that seems to be inherited.
2459  */
2460 static void
2461 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2462 {
2463         int                     i,
2464                                 j,
2465                                 k;
2466
2467         for (i = 0; i < numTables; i++)
2468         {
2469                 TableInfo  *tbinfo = &(tblinfo[i]);
2470                 int                     numParents;
2471                 TableInfo **parents;
2472                 TableInfo  *parent;
2473
2474                 /* Sequences and views never have parents */
2475                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2476                         tbinfo->relkind == RELKIND_VIEW)
2477                         continue;
2478
2479                 /* Don't bother computing anything for non-target tables, either */
2480                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2481                         continue;
2482
2483                 numParents = tbinfo->numParents;
2484                 parents = tbinfo->parents;
2485
2486                 if (numParents == 0)
2487                         continue;                       /* nothing to see here, move along */
2488
2489                 /* scan for inherited CHECK constraints */
2490                 for (j = 0; j < tbinfo->ncheck; j++)
2491                 {
2492                         ConstraintInfo *constr;
2493
2494                         constr = &(tbinfo->checkexprs[j]);
2495
2496                         for (k = 0; k < numParents; k++)
2497                         {
2498                                 int                     l;
2499
2500                                 parent = parents[k];
2501                                 for (l = 0; l < parent->ncheck; l++)
2502                                 {
2503                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2504
2505                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2506                                         {
2507                                                 constr->conislocal = false;
2508                                                 break;
2509                                         }
2510                                 }
2511                                 if (!constr->conislocal)
2512                                         break;
2513                         }
2514                 }
2515         }
2516 }
2517
2518
2519 /*
2520  * dumpDatabase:
2521  *      dump the database definition
2522  */
2523 static void
2524 dumpDatabase(Archive *fout)
2525 {
2526         DumpOptions *dopt = fout->dopt;
2527         PQExpBuffer dbQry = createPQExpBuffer();
2528         PQExpBuffer delQry = createPQExpBuffer();
2529         PQExpBuffer creaQry = createPQExpBuffer();
2530         PQExpBuffer labelq = createPQExpBuffer();
2531         PGconn     *conn = GetConnection(fout);
2532         PGresult   *res;
2533         int                     i_tableoid,
2534                                 i_oid,
2535                                 i_datname,
2536                                 i_dba,
2537                                 i_encoding,
2538                                 i_collate,
2539                                 i_ctype,
2540                                 i_frozenxid,
2541                                 i_minmxid,
2542                                 i_datacl,
2543                                 i_rdatacl,
2544                                 i_datistemplate,
2545                                 i_datconnlimit,
2546                                 i_tablespace;
2547         CatalogId       dbCatId;
2548         DumpId          dbDumpId;
2549         const char *datname,
2550                            *dba,
2551                            *encoding,
2552                            *collate,
2553                            *ctype,
2554                            *datacl,
2555                            *rdatacl,
2556                            *datistemplate,
2557                            *datconnlimit,
2558                            *tablespace;
2559         uint32          frozenxid,
2560                                 minmxid;
2561         char       *qdatname;
2562
2563         if (g_verbose)
2564                 write_msg(NULL, "saving database definition\n");
2565
2566         /* Fetch the database-level properties for this database */
2567         if (fout->remoteVersion >= 90600)
2568         {
2569                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2570                                                   "(%s datdba) AS dba, "
2571                                                   "pg_encoding_to_char(encoding) AS encoding, "
2572                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2573                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2574                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2575                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2576                                                   " AS datacl, "
2577                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2578                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2579                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2580                                                   " AS rdatacl, "
2581                                                   "datistemplate, datconnlimit, "
2582                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2583                                                   "shobj_description(oid, 'pg_database') AS description "
2584
2585                                                   "FROM pg_database "
2586                                                   "WHERE datname = current_database()",
2587                                                   username_subquery);
2588         }
2589         else if (fout->remoteVersion >= 90300)
2590         {
2591                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2592                                                   "(%s datdba) AS dba, "
2593                                                   "pg_encoding_to_char(encoding) AS encoding, "
2594                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2595                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2596                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2597                                                   "shobj_description(oid, 'pg_database') AS description "
2598
2599                                                   "FROM pg_database "
2600                                                   "WHERE datname = current_database()",
2601                                                   username_subquery);
2602         }
2603         else if (fout->remoteVersion >= 80400)
2604         {
2605                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2606                                                   "(%s datdba) AS dba, "
2607                                                   "pg_encoding_to_char(encoding) AS encoding, "
2608                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2609                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2610                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2611                                                   "shobj_description(oid, 'pg_database') AS description "
2612
2613                                                   "FROM pg_database "
2614                                                   "WHERE datname = current_database()",
2615                                                   username_subquery);
2616         }
2617         else if (fout->remoteVersion >= 80200)
2618         {
2619                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2620                                                   "(%s datdba) AS dba, "
2621                                                   "pg_encoding_to_char(encoding) AS encoding, "
2622                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2623                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2624                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2625                                                   "shobj_description(oid, 'pg_database') AS description "
2626
2627                                                   "FROM pg_database "
2628                                                   "WHERE datname = current_database()",
2629                                                   username_subquery);
2630         }
2631         else
2632         {
2633                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2634                                                   "(%s datdba) AS dba, "
2635                                                   "pg_encoding_to_char(encoding) AS encoding, "
2636                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2637                                                   "datacl, '' as rdatacl, datistemplate, "
2638                                                   "-1 as datconnlimit, "
2639                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2640                                                   "FROM pg_database "
2641                                                   "WHERE datname = current_database()",
2642                                                   username_subquery);
2643         }
2644
2645         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2646
2647         i_tableoid = PQfnumber(res, "tableoid");
2648         i_oid = PQfnumber(res, "oid");
2649         i_datname = PQfnumber(res, "datname");
2650         i_dba = PQfnumber(res, "dba");
2651         i_encoding = PQfnumber(res, "encoding");
2652         i_collate = PQfnumber(res, "datcollate");
2653         i_ctype = PQfnumber(res, "datctype");
2654         i_frozenxid = PQfnumber(res, "datfrozenxid");
2655         i_minmxid = PQfnumber(res, "datminmxid");
2656         i_datacl = PQfnumber(res, "datacl");
2657         i_rdatacl = PQfnumber(res, "rdatacl");
2658         i_datistemplate = PQfnumber(res, "datistemplate");
2659         i_datconnlimit = PQfnumber(res, "datconnlimit");
2660         i_tablespace = PQfnumber(res, "tablespace");
2661
2662         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2663         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2664         datname = PQgetvalue(res, 0, i_datname);
2665         dba = PQgetvalue(res, 0, i_dba);
2666         encoding = PQgetvalue(res, 0, i_encoding);
2667         collate = PQgetvalue(res, 0, i_collate);
2668         ctype = PQgetvalue(res, 0, i_ctype);
2669         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2670         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2671         datacl = PQgetvalue(res, 0, i_datacl);
2672         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2673         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2674         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2675         tablespace = PQgetvalue(res, 0, i_tablespace);
2676
2677         qdatname = pg_strdup(fmtId(datname));
2678
2679         /*
2680          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2681          * and tablespace since those can't be altered later.  Other DB properties
2682          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2683          * after reconnecting to the target DB.
2684          */
2685         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2686                                           qdatname);
2687         if (strlen(encoding) > 0)
2688         {
2689                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2690                 appendStringLiteralAH(creaQry, encoding, fout);
2691         }
2692         if (strlen(collate) > 0)
2693         {
2694                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2695                 appendStringLiteralAH(creaQry, collate, fout);
2696         }
2697         if (strlen(ctype) > 0)
2698         {
2699                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2700                 appendStringLiteralAH(creaQry, ctype, fout);
2701         }
2702
2703         /*
2704          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2705          * thing; the decision whether to specify a tablespace should be left till
2706          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2707          * label the DATABASE entry with the tablespace and let the normal
2708          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2709          * attention to default_tablespace, so that won't work.
2710          */
2711         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2712                 !dopt->outputNoTablespaces)
2713                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2714                                                   fmtId(tablespace));
2715         appendPQExpBufferStr(creaQry, ";\n");
2716
2717         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2718                                           qdatname);
2719
2720         dbDumpId = createDumpId();
2721
2722         ArchiveEntry(fout,
2723                                  dbCatId,               /* catalog ID */
2724                                  dbDumpId,              /* dump ID */
2725                                  datname,               /* Name */
2726                                  NULL,                  /* Namespace */
2727                                  NULL,                  /* Tablespace */
2728                                  dba,                   /* Owner */
2729                                  "DATABASE",    /* Desc */
2730                                  SECTION_PRE_DATA,      /* Section */
2731                                  creaQry->data, /* Create */
2732                                  delQry->data,  /* Del */
2733                                  NULL,                  /* Copy */
2734                                  NULL,                  /* Deps */
2735                                  0,                             /* # Deps */
2736                                  NULL,                  /* Dumper */
2737                                  NULL);                 /* Dumper Arg */
2738
2739         /* Compute correct tag for archive entry */
2740         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2741
2742         /* Dump DB comment if any */
2743         if (fout->remoteVersion >= 80200)
2744         {
2745                 /*
2746                  * 8.2 and up keep comments on shared objects in a shared table, so we
2747                  * cannot use the dumpComment() code used for other database objects.
2748                  * Be careful that the ArchiveEntry parameters match that function.
2749                  */
2750                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2751
2752                 if (comment && *comment && !dopt->no_comments)
2753                 {
2754                         resetPQExpBuffer(dbQry);
2755
2756                         /*
2757                          * Generates warning when loaded into a differently-named
2758                          * database.
2759                          */
2760                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2761                         appendStringLiteralAH(dbQry, comment, fout);
2762                         appendPQExpBufferStr(dbQry, ";\n");
2763
2764                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2765                                                  labelq->data, NULL, NULL, dba,
2766                                                  "COMMENT", SECTION_NONE,
2767                                                  dbQry->data, "", NULL,
2768                                                  &(dbDumpId), 1,
2769                                                  NULL, NULL);
2770                 }
2771         }
2772         else
2773         {
2774                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2775                                         dbCatId, 0, dbDumpId);
2776         }
2777
2778         /* Dump DB security label, if enabled */
2779         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2780         {
2781                 PGresult   *shres;
2782                 PQExpBuffer seclabelQry;
2783
2784                 seclabelQry = createPQExpBuffer();
2785
2786                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2787                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2788                 resetPQExpBuffer(seclabelQry);
2789                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2790                 if (seclabelQry->len > 0)
2791                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2792                                                  labelq->data, NULL, NULL, dba,
2793                                                  "SECURITY LABEL", SECTION_NONE,
2794                                                  seclabelQry->data, "", NULL,
2795                                                  &(dbDumpId), 1,
2796                                                  NULL, NULL);
2797                 destroyPQExpBuffer(seclabelQry);
2798                 PQclear(shres);
2799         }
2800
2801         /*
2802          * Dump ACL if any.  Note that we do not support initial privileges
2803          * (pg_init_privs) on databases.
2804          */
2805         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2806                         qdatname, NULL, NULL,
2807                         dba, datacl, rdatacl, "", "");
2808
2809         /*
2810          * Now construct a DATABASE PROPERTIES archive entry to restore any
2811          * non-default database-level properties.  (The reason this must be
2812          * separate is that we cannot put any additional commands into the TOC
2813          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2814          * in an implicit transaction block, and the backend won't allow CREATE
2815          * DATABASE in that context.)
2816          */
2817         resetPQExpBuffer(creaQry);
2818         resetPQExpBuffer(delQry);
2819
2820         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2821                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2822                                                   qdatname, datconnlimit);
2823
2824         if (strcmp(datistemplate, "t") == 0)
2825         {
2826                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2827                                                   qdatname);
2828
2829                 /*
2830                  * The backend won't accept DROP DATABASE on a template database.  We
2831                  * can deal with that by removing the template marking before the DROP
2832                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2833                  * since no such command is currently supported, fake it with a direct
2834                  * UPDATE on pg_database.
2835                  */
2836                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2837                                                          "SET datistemplate = false WHERE datname = ");
2838                 appendStringLiteralAH(delQry, datname, fout);
2839                 appendPQExpBufferStr(delQry, ";\n");
2840         }
2841
2842         /* Add database-specific SET options */
2843         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2844
2845         /*
2846          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2847          * entry, too, for lack of a better place.
2848          */
2849         if (dopt->binary_upgrade)
2850         {
2851                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2852                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2853                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2854                                                   "WHERE datname = ",
2855                                                   frozenxid, minmxid);
2856                 appendStringLiteralAH(creaQry, datname, fout);
2857                 appendPQExpBufferStr(creaQry, ";\n");
2858         }
2859
2860         if (creaQry->len > 0)
2861                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2862                                          datname, NULL, NULL, dba,
2863                                          "DATABASE PROPERTIES", SECTION_PRE_DATA,
2864                                          creaQry->data, delQry->data, NULL,
2865                                          &(dbDumpId), 1,
2866                                          NULL, NULL);
2867
2868         /*
2869          * pg_largeobject comes from the old system intact, so set its
2870          * relfrozenxids and relminmxids.
2871          */
2872         if (dopt->binary_upgrade)
2873         {
2874                 PGresult   *lo_res;
2875                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2876                 PQExpBuffer loOutQry = createPQExpBuffer();
2877                 int                     i_relfrozenxid,
2878                                         i_relminmxid;
2879
2880                 /*
2881                  * pg_largeobject
2882                  */
2883                 if (fout->remoteVersion >= 90300)
2884                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2885                                                           "FROM pg_catalog.pg_class\n"
2886                                                           "WHERE oid = %u;\n",
2887                                                           LargeObjectRelationId);
2888                 else
2889                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2890                                                           "FROM pg_catalog.pg_class\n"
2891                                                           "WHERE oid = %u;\n",
2892                                                           LargeObjectRelationId);
2893
2894                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2895
2896                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2897                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2898
2899                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2900                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2901                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2902                                                   "WHERE oid = %u;\n",
2903                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2904                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2905                                                   LargeObjectRelationId);
2906                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2907                                          "pg_largeobject", NULL, NULL, "",
2908                                          "pg_largeobject", SECTION_PRE_DATA,
2909                                          loOutQry->data, "", NULL,
2910                                          NULL, 0,
2911                                          NULL, NULL);
2912
2913                 PQclear(lo_res);
2914
2915                 destroyPQExpBuffer(loFrozenQry);
2916                 destroyPQExpBuffer(loOutQry);
2917         }
2918
2919         PQclear(res);
2920
2921         free(qdatname);
2922         destroyPQExpBuffer(dbQry);
2923         destroyPQExpBuffer(delQry);
2924         destroyPQExpBuffer(creaQry);
2925         destroyPQExpBuffer(labelq);
2926 }
2927
2928 /*
2929  * Collect any database-specific or role-and-database-specific SET options
2930  * for this database, and append them to outbuf.
2931  */
2932 static void
2933 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
2934                                    const char *dbname, Oid dboid)
2935 {
2936         PGconn     *conn = GetConnection(AH);
2937         PQExpBuffer buf = createPQExpBuffer();
2938         PGresult   *res;
2939         int                     count = 1;
2940
2941         /*
2942          * First collect database-specific options.  Pre-8.4 server versions lack
2943          * unnest(), so we do this the hard way by querying once per subscript.
2944          */
2945         for (;;)
2946         {
2947                 if (AH->remoteVersion >= 90000)
2948                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
2949                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
2950                                                           count, dboid);
2951                 else
2952                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
2953
2954                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
2955
2956                 if (PQntuples(res) == 1 &&
2957                         !PQgetisnull(res, 0, 0))
2958                 {
2959                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
2960                                                                    "DATABASE", dbname, NULL, NULL,
2961                                                                    outbuf);
2962                         PQclear(res);
2963                         count++;
2964                 }
2965                 else
2966                 {
2967                         PQclear(res);
2968                         break;
2969                 }
2970         }
2971
2972         /* Now look for role-and-database-specific options */
2973         if (AH->remoteVersion >= 90000)
2974         {
2975                 /* Here we can assume we have unnest() */
2976                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
2977                                                   "FROM pg_db_role_setting s, pg_roles r "
2978                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
2979                                                   dboid);
2980
2981                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
2982
2983                 if (PQntuples(res) > 0)
2984                 {
2985                         int                     i;
2986
2987                         for (i = 0; i < PQntuples(res); i++)
2988                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
2989                                                                            "ROLE", PQgetvalue(res, i, 0),
2990                                                                            "DATABASE", dbname,
2991                                                                            outbuf);
2992                 }
2993
2994                 PQclear(res);
2995         }
2996
2997         destroyPQExpBuffer(buf);
2998 }
2999
3000 /*
3001  * dumpEncoding: put the correct encoding into the archive
3002  */
3003 static void
3004 dumpEncoding(Archive *AH)
3005 {
3006         const char *encname = pg_encoding_to_char(AH->encoding);
3007         PQExpBuffer qry = createPQExpBuffer();
3008
3009         if (g_verbose)
3010                 write_msg(NULL, "saving encoding = %s\n", encname);
3011
3012         appendPQExpBufferStr(qry, "SET client_encoding = ");
3013         appendStringLiteralAH(qry, encname, AH);
3014         appendPQExpBufferStr(qry, ";\n");
3015
3016         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3017                                  "ENCODING", NULL, NULL, "",
3018                                  "ENCODING", SECTION_PRE_DATA,
3019                                  qry->data, "", NULL,
3020                                  NULL, 0,
3021                                  NULL, NULL);
3022
3023         destroyPQExpBuffer(qry);
3024 }
3025
3026
3027 /*
3028  * dumpStdStrings: put the correct escape string behavior into the archive
3029  */
3030 static void
3031 dumpStdStrings(Archive *AH)
3032 {
3033         const char *stdstrings = AH->std_strings ? "on" : "off";
3034         PQExpBuffer qry = createPQExpBuffer();
3035
3036         if (g_verbose)
3037                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3038                                   stdstrings);
3039
3040         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3041                                           stdstrings);
3042
3043         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3044                                  "STDSTRINGS", NULL, NULL, "",
3045                                  "STDSTRINGS", SECTION_PRE_DATA,
3046                                  qry->data, "", NULL,
3047                                  NULL, 0,
3048                                  NULL, NULL);
3049
3050         destroyPQExpBuffer(qry);
3051 }
3052
3053 /*
3054  * dumpSearchPath: record the active search_path in the archive
3055  */
3056 static void
3057 dumpSearchPath(Archive *AH)
3058 {
3059         PQExpBuffer qry = createPQExpBuffer();
3060         PQExpBuffer path = createPQExpBuffer();
3061         PGresult   *res;
3062         char      **schemanames = NULL;
3063         int                     nschemanames = 0;
3064         int                     i;
3065
3066         /*
3067          * We use the result of current_schemas(), not the search_path GUC,
3068          * because that might contain wildcards such as "$user", which won't
3069          * necessarily have the same value during restore.  Also, this way avoids
3070          * listing schemas that may appear in search_path but not actually exist,
3071          * which seems like a prudent exclusion.
3072          */
3073         res = ExecuteSqlQueryForSingleRow(AH,
3074                                                                           "SELECT pg_catalog.current_schemas(false)");
3075
3076         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3077                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3078
3079         /*
3080          * We use set_config(), not a simple "SET search_path" command, because
3081          * the latter has less-clean behavior if the search path is empty.  While
3082          * that's likely to get fixed at some point, it seems like a good idea to
3083          * be as backwards-compatible as possible in what we put into archives.
3084          */
3085         for (i = 0; i < nschemanames; i++)
3086         {
3087                 if (i > 0)
3088                         appendPQExpBufferStr(path, ", ");
3089                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3090         }
3091
3092         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3093         appendStringLiteralAH(qry, path->data, AH);
3094         appendPQExpBufferStr(qry, ", false);\n");
3095
3096         if (g_verbose)
3097                 write_msg(NULL, "saving search_path = %s\n", path->data);
3098
3099         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3100                                  "SEARCHPATH", NULL, NULL, "",
3101                                  "SEARCHPATH", SECTION_PRE_DATA,
3102                                  qry->data, "", NULL,
3103                                  NULL, 0,
3104                                  NULL, NULL);
3105
3106         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3107         AH->searchpath = pg_strdup(qry->data);
3108
3109         if (schemanames)
3110                 free(schemanames);
3111         PQclear(res);
3112         destroyPQExpBuffer(qry);
3113         destroyPQExpBuffer(path);
3114 }
3115
3116
3117 /*
3118  * getBlobs:
3119  *      Collect schema-level data about large objects
3120  */
3121 static void
3122 getBlobs(Archive *fout)
3123 {
3124         DumpOptions *dopt = fout->dopt;
3125         PQExpBuffer blobQry = createPQExpBuffer();
3126         BlobInfo   *binfo;
3127         DumpableObject *bdata;
3128         PGresult   *res;
3129         int                     ntups;
3130         int                     i;
3131         int                     i_oid;
3132         int                     i_lomowner;
3133         int                     i_lomacl;
3134         int                     i_rlomacl;
3135         int                     i_initlomacl;
3136         int                     i_initrlomacl;
3137
3138         /* Verbose message */
3139         if (g_verbose)
3140                 write_msg(NULL, "reading large objects\n");
3141
3142         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3143         if (fout->remoteVersion >= 90600)
3144         {
3145                 PQExpBuffer acl_subquery = createPQExpBuffer();
3146                 PQExpBuffer racl_subquery = createPQExpBuffer();
3147                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3148                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3149
3150                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3151                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3152                                                 dopt->binary_upgrade);
3153
3154                 appendPQExpBuffer(blobQry,
3155                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3156                                                   "%s AS lomacl, "
3157                                                   "%s AS rlomacl, "
3158                                                   "%s AS initlomacl, "
3159                                                   "%s AS initrlomacl "
3160                                                   "FROM pg_largeobject_metadata l "
3161                                                   "LEFT JOIN pg_init_privs pip ON "
3162                                                   "(l.oid = pip.objoid "
3163                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3164                                                   "AND pip.objsubid = 0) ",
3165                                                   username_subquery,
3166                                                   acl_subquery->data,
3167                                                   racl_subquery->data,
3168                                                   init_acl_subquery->data,
3169                                                   init_racl_subquery->data);
3170
3171                 destroyPQExpBuffer(acl_subquery);
3172                 destroyPQExpBuffer(racl_subquery);
3173                 destroyPQExpBuffer(init_acl_subquery);
3174                 destroyPQExpBuffer(init_racl_subquery);
3175         }
3176         else if (fout->remoteVersion >= 90000)
3177                 appendPQExpBuffer(blobQry,
3178                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3179                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3180                                                   "NULL AS initrlomacl "
3181                                                   " FROM pg_largeobject_metadata",
3182                                                   username_subquery);
3183         else
3184                 appendPQExpBufferStr(blobQry,
3185                                                          "SELECT DISTINCT loid AS oid, "
3186                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3187                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3188                                                          "NULL::oid AS initrlomacl "
3189                                                          " FROM pg_largeobject");
3190
3191         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3192
3193         i_oid = PQfnumber(res, "oid");
3194         i_lomowner = PQfnumber(res, "rolname");
3195         i_lomacl = PQfnumber(res, "lomacl");
3196         i_rlomacl = PQfnumber(res, "rlomacl");
3197         i_initlomacl = PQfnumber(res, "initlomacl");
3198         i_initrlomacl = PQfnumber(res, "initrlomacl");
3199
3200         ntups = PQntuples(res);
3201
3202         /*
3203          * Each large object has its own BLOB archive entry.
3204          */
3205         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3206
3207         for (i = 0; i < ntups; i++)
3208         {
3209                 binfo[i].dobj.objType = DO_BLOB;
3210                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3211                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3212                 AssignDumpId(&binfo[i].dobj);
3213
3214                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3215                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3216                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3217                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3218                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3219                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3220
3221                 if (PQgetisnull(res, i, i_lomacl) &&
3222                         PQgetisnull(res, i, i_rlomacl) &&
3223                         PQgetisnull(res, i, i_initlomacl) &&
3224                         PQgetisnull(res, i, i_initrlomacl))
3225                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3226
3227                 /*
3228                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3229                  * data, as it will be copied by pg_upgrade, which simply copies the
3230                  * pg_largeobject table. We *do* however dump out anything but the
3231                  * data, as pg_upgrade copies just pg_largeobject, but not
3232                  * pg_largeobject_metadata, after the dump is restored.
3233                  */
3234                 if (dopt->binary_upgrade)
3235                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3236         }
3237
3238         /*
3239          * If we have any large objects, a "BLOBS" archive entry is needed. This
3240          * is just a placeholder for sorting; it carries no data now.
3241          */
3242         if (ntups > 0)
3243         {
3244                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3245                 bdata->objType = DO_BLOB_DATA;
3246                 bdata->catId = nilCatalogId;
3247                 AssignDumpId(bdata);
3248                 bdata->name = pg_strdup("BLOBS");
3249         }
3250
3251         PQclear(res);
3252         destroyPQExpBuffer(blobQry);
3253 }
3254
3255 /*
3256  * dumpBlob
3257  *
3258  * dump the definition (metadata) of the given large object
3259  */
3260 static void
3261 dumpBlob(Archive *fout, BlobInfo *binfo)
3262 {
3263         PQExpBuffer cquery = createPQExpBuffer();
3264         PQExpBuffer dquery = createPQExpBuffer();
3265
3266         appendPQExpBuffer(cquery,
3267                                           "SELECT pg_catalog.lo_create('%s');\n",
3268                                           binfo->dobj.name);
3269
3270         appendPQExpBuffer(dquery,
3271                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3272                                           binfo->dobj.name);
3273
3274         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3275                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3276                                          binfo->dobj.name,
3277                                          NULL, NULL,
3278                                          binfo->rolname,
3279                                          "BLOB", SECTION_PRE_DATA,
3280                                          cquery->data, dquery->data, NULL,
3281                                          NULL, 0,
3282                                          NULL, NULL);
3283
3284         /* Dump comment if any */
3285         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3286                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3287                                         NULL, binfo->rolname,
3288                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3289
3290         /* Dump security label if any */
3291         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3292                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3293                                          NULL, binfo->rolname,
3294                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3295
3296         /* Dump ACL if any */
3297         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3298                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3299                                 binfo->dobj.name, NULL,
3300                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3301                                 binfo->initblobacl, binfo->initrblobacl);
3302
3303         destroyPQExpBuffer(cquery);
3304         destroyPQExpBuffer(dquery);
3305 }
3306
3307 /*
3308  * dumpBlobs:
3309  *      dump the data contents of all large objects
3310  */
3311 static int
3312 dumpBlobs(Archive *fout, void *arg)
3313 {
3314         const char *blobQry;
3315         const char *blobFetchQry;
3316         PGconn     *conn = GetConnection(fout);
3317         PGresult   *res;
3318         char            buf[LOBBUFSIZE];
3319         int                     ntups;
3320         int                     i;
3321         int                     cnt;
3322
3323         if (g_verbose)
3324                 write_msg(NULL, "saving large objects\n");
3325
3326         /*
3327          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3328          * the already-in-memory dumpable objects instead...
3329          */
3330         if (fout->remoteVersion >= 90000)
3331                 blobQry =
3332                         "DECLARE bloboid CURSOR FOR "
3333                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3334         else
3335                 blobQry =
3336                         "DECLARE bloboid CURSOR FOR "
3337                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3338
3339         ExecuteSqlStatement(fout, blobQry);
3340
3341         /* Command to fetch from cursor */
3342         blobFetchQry = "FETCH 1000 IN bloboid";
3343
3344         do
3345         {
3346                 /* Do a fetch */
3347                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3348
3349                 /* Process the tuples, if any */
3350                 ntups = PQntuples(res);
3351                 for (i = 0; i < ntups; i++)
3352                 {
3353                         Oid                     blobOid;
3354                         int                     loFd;
3355
3356                         blobOid = atooid(PQgetvalue(res, i, 0));
3357                         /* Open the BLOB */
3358                         loFd = lo_open(conn, blobOid, INV_READ);
3359                         if (loFd == -1)
3360                                 exit_horribly(NULL, "could not open large object %u: %s",
3361                                                           blobOid, PQerrorMessage(conn));
3362
3363                         StartBlob(fout, blobOid);
3364
3365                         /* Now read it in chunks, sending data to archive */
3366                         do
3367                         {
3368                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3369                                 if (cnt < 0)
3370                                         exit_horribly(NULL, "error reading large object %u: %s",
3371                                                                   blobOid, PQerrorMessage(conn));
3372
3373                                 WriteData(fout, buf, cnt);
3374                         } while (cnt > 0);
3375
3376                         lo_close(conn, loFd);
3377
3378                         EndBlob(fout, blobOid);
3379                 }
3380
3381                 PQclear(res);
3382         } while (ntups > 0);
3383
3384         return 1;
3385 }
3386
3387 /*
3388  * getPolicies
3389  *        get information about policies on a dumpable table.
3390  */
3391 void
3392 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3393 {
3394         PQExpBuffer query;
3395         PGresult   *res;
3396         PolicyInfo *polinfo;
3397         int                     i_oid;
3398         int                     i_tableoid;
3399         int                     i_polname;
3400         int                     i_polcmd;
3401         int                     i_polpermissive;
3402         int                     i_polroles;
3403         int                     i_polqual;
3404         int                     i_polwithcheck;
3405         int                     i,
3406                                 j,
3407                                 ntups;
3408
3409         if (fout->remoteVersion < 90500)
3410                 return;
3411
3412         query = createPQExpBuffer();
3413
3414         for (i = 0; i < numTables; i++)
3415         {
3416                 TableInfo  *tbinfo = &tblinfo[i];
3417
3418                 /* Ignore row security on tables not to be dumped */
3419                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3420                         continue;
3421
3422                 if (g_verbose)
3423                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3424                                           tbinfo->dobj.namespace->dobj.name,
3425                                           tbinfo->dobj.name);
3426
3427                 /*
3428                  * Get row security enabled information for the table. We represent
3429                  * RLS being enabled on a table by creating a PolicyInfo object with
3430                  * null polname.
3431                  */
3432                 if (tbinfo->rowsec)
3433                 {
3434                         /*
3435                          * Note: use tableoid 0 so that this object won't be mistaken for
3436                          * something that pg_depend entries apply to.
3437                          */
3438                         polinfo = pg_malloc(sizeof(PolicyInfo));
3439                         polinfo->dobj.objType = DO_POLICY;
3440                         polinfo->dobj.catId.tableoid = 0;
3441                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3442                         AssignDumpId(&polinfo->dobj);
3443                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3444                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3445                         polinfo->poltable = tbinfo;
3446                         polinfo->polname = NULL;
3447                         polinfo->polcmd = '\0';
3448                         polinfo->polpermissive = 0;
3449                         polinfo->polroles = NULL;
3450                         polinfo->polqual = NULL;
3451                         polinfo->polwithcheck = NULL;
3452                 }
3453
3454                 if (g_verbose)
3455                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3456                                           tbinfo->dobj.namespace->dobj.name,
3457                                           tbinfo->dobj.name);
3458
3459                 resetPQExpBuffer(query);
3460
3461                 /* Get the policies for the table. */
3462                 if (fout->remoteVersion >= 100000)
3463                         appendPQExpBuffer(query,
3464                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3465                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3466                                                           "   pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
3467                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3468                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3469                                                           "FROM pg_catalog.pg_policy pol "
3470                                                           "WHERE polrelid = '%u'",
3471                                                           tbinfo->dobj.catId.oid);
3472                 else
3473                         appendPQExpBuffer(query,
3474                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3475                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3476                                                           "   pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
3477                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3478                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3479                                                           "FROM pg_catalog.pg_policy pol "
3480                                                           "WHERE polrelid = '%u'",
3481                                                           tbinfo->dobj.catId.oid);
3482                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3483
3484                 ntups = PQntuples(res);
3485
3486                 if (ntups == 0)
3487                 {
3488                         /*
3489                          * No explicit policies to handle (only the default-deny policy,
3490                          * which is handled as part of the table definition).  Clean up
3491                          * and return.
3492                          */
3493                         PQclear(res);
3494                         continue;
3495                 }
3496
3497                 i_oid = PQfnumber(res, "oid");
3498                 i_tableoid = PQfnumber(res, "tableoid");
3499                 i_polname = PQfnumber(res, "polname");
3500                 i_polcmd = PQfnumber(res, "polcmd");
3501                 i_polpermissive = PQfnumber(res, "polpermissive");
3502                 i_polroles = PQfnumber(res, "polroles");
3503                 i_polqual = PQfnumber(res, "polqual");
3504                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3505
3506                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3507
3508                 for (j = 0; j < ntups; j++)
3509                 {
3510                         polinfo[j].dobj.objType = DO_POLICY;
3511                         polinfo[j].dobj.catId.tableoid =
3512                                 atooid(PQgetvalue(res, j, i_tableoid));
3513                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3514                         AssignDumpId(&polinfo[j].dobj);
3515                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3516                         polinfo[j].poltable = tbinfo;
3517                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3518                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3519
3520                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3521                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3522
3523                         if (PQgetisnull(res, j, i_polroles))
3524                                 polinfo[j].polroles = NULL;
3525                         else
3526                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3527
3528                         if (PQgetisnull(res, j, i_polqual))
3529                                 polinfo[j].polqual = NULL;
3530                         else
3531                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3532
3533                         if (PQgetisnull(res, j, i_polwithcheck))
3534                                 polinfo[j].polwithcheck = NULL;
3535                         else
3536                                 polinfo[j].polwithcheck
3537                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3538                 }
3539                 PQclear(res);
3540         }
3541         destroyPQExpBuffer(query);
3542 }
3543
3544 /*
3545  * dumpPolicy
3546  *        dump the definition of the given policy
3547  */
3548 static void
3549 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3550 {
3551         DumpOptions *dopt = fout->dopt;
3552         TableInfo  *tbinfo = polinfo->poltable;
3553         PQExpBuffer query;
3554         PQExpBuffer delqry;
3555         const char *cmd;
3556         char       *tag;
3557
3558         if (dopt->dataOnly)
3559                 return;
3560
3561         /*
3562          * If polname is NULL, then this record is just indicating that ROW LEVEL
3563          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3564          * ROW LEVEL SECURITY.
3565          */
3566         if (polinfo->polname == NULL)
3567         {
3568                 query = createPQExpBuffer();
3569
3570                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3571                                                   fmtQualifiedDumpable(tbinfo));
3572
3573                 /*
3574                  * We must emit the ROW SECURITY object's dependency on its table
3575                  * explicitly, because it will not match anything in pg_depend (unlike
3576                  * the case for other PolicyInfo objects).
3577                  */
3578                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3579                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3580                                                  polinfo->dobj.name,
3581                                                  polinfo->dobj.namespace->dobj.name,
3582                                                  NULL,
3583                                                  tbinfo->rolname,
3584                                                  "ROW SECURITY", SECTION_POST_DATA,
3585                                                  query->data, "", NULL,
3586                                                  &(tbinfo->dobj.dumpId), 1,
3587                                                  NULL, NULL);
3588
3589                 destroyPQExpBuffer(query);
3590                 return;
3591         }
3592
3593         if (polinfo->polcmd == '*')
3594                 cmd = "";
3595         else if (polinfo->polcmd == 'r')
3596                 cmd = " FOR SELECT";
3597         else if (polinfo->polcmd == 'a')
3598                 cmd = " FOR INSERT";
3599         else if (polinfo->polcmd == 'w')
3600                 cmd = " FOR UPDATE";
3601         else if (polinfo->polcmd == 'd')
3602                 cmd = " FOR DELETE";
3603         else
3604         {
3605                 write_msg(NULL, "unexpected policy command type: %c\n",
3606                                   polinfo->polcmd);
3607                 exit_nicely(1);
3608         }
3609
3610         query = createPQExpBuffer();
3611         delqry = createPQExpBuffer();
3612
3613         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3614
3615         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3616                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3617
3618         if (polinfo->polroles != NULL)
3619                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3620
3621         if (polinfo->polqual != NULL)
3622                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3623
3624         if (polinfo->polwithcheck != NULL)
3625                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3626
3627         appendPQExpBuffer(query, ";\n");
3628
3629         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3630         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3631
3632         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3633
3634         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3635                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3636                                          tag,
3637                                          polinfo->dobj.namespace->dobj.name,
3638                                          NULL,
3639                                          tbinfo->rolname,
3640                                          "POLICY", SECTION_POST_DATA,
3641                                          query->data, delqry->data, NULL,
3642                                          NULL, 0,
3643                                          NULL, NULL);
3644
3645         free(tag);
3646         destroyPQExpBuffer(query);
3647         destroyPQExpBuffer(delqry);
3648 }
3649
3650 /*
3651  * getPublications
3652  *        get information about publications
3653  */
3654 void
3655 getPublications(Archive *fout)
3656 {
3657         DumpOptions *dopt = fout->dopt;
3658         PQExpBuffer query;
3659         PGresult   *res;
3660         PublicationInfo *pubinfo;
3661         int                     i_tableoid;
3662         int                     i_oid;
3663         int                     i_pubname;
3664         int                     i_rolname;
3665         int                     i_puballtables;
3666         int                     i_pubinsert;
3667         int                     i_pubupdate;
3668         int                     i_pubdelete;
3669         int                     i_pubtruncate;
3670         int                     i,
3671                                 ntups;
3672
3673         if (dopt->no_publications || fout->remoteVersion < 100000)
3674                 return;
3675
3676         query = createPQExpBuffer();
3677
3678         resetPQExpBuffer(query);
3679
3680         /* Get the publications. */
3681         if (fout->remoteVersion >= 110000)
3682                 appendPQExpBuffer(query,
3683                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3684                                                   "(%s p.pubowner) AS rolname, "
3685                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3686                                                   "FROM pg_publication p",
3687                                                   username_subquery);
3688         else
3689                 appendPQExpBuffer(query,
3690                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3691                                                   "(%s p.pubowner) AS rolname, "
3692                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3693                                                   "FROM pg_publication p",
3694                                                   username_subquery);
3695
3696         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3697
3698         ntups = PQntuples(res);
3699
3700         i_tableoid = PQfnumber(res, "tableoid");
3701         i_oid = PQfnumber(res, "oid");
3702         i_pubname = PQfnumber(res, "pubname");
3703         i_rolname = PQfnumber(res, "rolname");
3704         i_puballtables = PQfnumber(res, "puballtables");
3705         i_pubinsert = PQfnumber(res, "pubinsert");
3706         i_pubupdate = PQfnumber(res, "pubupdate");
3707         i_pubdelete = PQfnumber(res, "pubdelete");
3708         i_pubtruncate = PQfnumber(res, "pubtruncate");
3709
3710         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3711
3712         for (i = 0; i < ntups; i++)
3713         {
3714                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3715                 pubinfo[i].dobj.catId.tableoid =
3716                         atooid(PQgetvalue(res, i, i_tableoid));
3717                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3718                 AssignDumpId(&pubinfo[i].dobj);
3719                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3720                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3721                 pubinfo[i].puballtables =
3722                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3723                 pubinfo[i].pubinsert =
3724                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3725                 pubinfo[i].pubupdate =
3726                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3727                 pubinfo[i].pubdelete =
3728                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3729                 pubinfo[i].pubtruncate =
3730                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3731
3732                 if (strlen(pubinfo[i].rolname) == 0)
3733                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3734                                           pubinfo[i].dobj.name);
3735
3736                 /* Decide whether we want to dump it */
3737                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3738         }
3739         PQclear(res);
3740
3741         destroyPQExpBuffer(query);
3742 }
3743
3744 /*
3745  * dumpPublication
3746  *        dump the definition of the given publication
3747  */
3748 static void
3749 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3750 {
3751         PQExpBuffer delq;
3752         PQExpBuffer query;
3753         char       *qpubname;
3754         bool            first = true;
3755
3756         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3757                 return;
3758
3759         delq = createPQExpBuffer();
3760         query = createPQExpBuffer();
3761
3762         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3763
3764         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3765                                           qpubname);
3766
3767         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3768                                           qpubname);
3769
3770         if (pubinfo->puballtables)
3771                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3772
3773         appendPQExpBufferStr(query, " WITH (publish = '");
3774         if (pubinfo->pubinsert)
3775         {
3776                 appendPQExpBufferStr(query, "insert");
3777                 first = false;
3778         }
3779
3780         if (pubinfo->pubupdate)
3781         {
3782                 if (!first)
3783                         appendPQExpBufferStr(query, ", ");
3784
3785                 appendPQExpBufferStr(query, "update");
3786                 first = false;
3787         }
3788
3789         if (pubinfo->pubdelete)
3790         {
3791                 if (!first)
3792                         appendPQExpBufferStr(query, ", ");
3793
3794                 appendPQExpBufferStr(query, "delete");
3795                 first = false;
3796         }
3797
3798         if (pubinfo->pubtruncate)
3799         {
3800                 if (!first)
3801                         appendPQExpBufferStr(query, ", ");
3802
3803                 appendPQExpBufferStr(query, "truncate");
3804                 first = false;
3805         }
3806
3807         appendPQExpBufferStr(query, "');\n");
3808
3809         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3810                                  pubinfo->dobj.name,
3811                                  NULL,
3812                                  NULL,
3813                                  pubinfo->rolname,
3814                                  "PUBLICATION", SECTION_POST_DATA,
3815                                  query->data, delq->data, NULL,
3816                                  NULL, 0,
3817                                  NULL, NULL);
3818
3819         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3820                 dumpComment(fout, "PUBLICATION", qpubname,
3821                                         NULL, pubinfo->rolname,
3822                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3823
3824         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3825                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3826                                          NULL, pubinfo->rolname,
3827                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3828
3829         destroyPQExpBuffer(delq);
3830         destroyPQExpBuffer(query);
3831         free(qpubname);
3832 }
3833
3834 /*
3835  * getPublicationTables
3836  *        get information about publication membership for dumpable tables.
3837  */
3838 void
3839 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3840 {
3841         PQExpBuffer query;
3842         PGresult   *res;
3843         PublicationRelInfo *pubrinfo;
3844         DumpOptions *dopt = fout->dopt;
3845         int                     i_tableoid;
3846         int                     i_oid;
3847         int                     i_pubname;
3848         int                     i,
3849                                 j,
3850                                 ntups;
3851
3852         if (dopt->no_publications || fout->remoteVersion < 100000)
3853                 return;
3854
3855         query = createPQExpBuffer();
3856
3857         for (i = 0; i < numTables; i++)
3858         {
3859                 TableInfo  *tbinfo = &tblinfo[i];
3860
3861                 /* Only plain tables can be aded to publications. */
3862                 if (tbinfo->relkind != RELKIND_RELATION)
3863                         continue;
3864
3865                 /*
3866                  * Ignore publication membership of tables whose definitions are not
3867                  * to be dumped.
3868                  */
3869                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3870                         continue;
3871
3872                 if (g_verbose)
3873                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3874                                           tbinfo->dobj.namespace->dobj.name,
3875                                           tbinfo->dobj.name);
3876
3877                 resetPQExpBuffer(query);
3878
3879                 /* Get the publication membership for the table. */
3880                 appendPQExpBuffer(query,
3881                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3882                                                   "FROM pg_publication_rel pr, pg_publication p "
3883                                                   "WHERE pr.prrelid = '%u'"
3884                                                   "  AND p.oid = pr.prpubid",
3885                                                   tbinfo->dobj.catId.oid);
3886                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3887
3888                 ntups = PQntuples(res);
3889
3890                 if (ntups == 0)
3891                 {
3892                         /*
3893                          * Table is not member of any publications. Clean up and return.
3894                          */
3895                         PQclear(res);
3896                         continue;
3897                 }
3898
3899                 i_tableoid = PQfnumber(res, "tableoid");
3900                 i_oid = PQfnumber(res, "oid");
3901                 i_pubname = PQfnumber(res, "pubname");
3902
3903                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3904
3905                 for (j = 0; j < ntups; j++)
3906                 {
3907                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3908                         pubrinfo[j].dobj.catId.tableoid =
3909                                 atooid(PQgetvalue(res, j, i_tableoid));
3910                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3911                         AssignDumpId(&pubrinfo[j].dobj);
3912                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3913                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3914                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3915                         pubrinfo[j].pubtable = tbinfo;
3916
3917                         /* Decide whether we want to dump it */
3918                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
3919                 }
3920                 PQclear(res);
3921         }
3922         destroyPQExpBuffer(query);
3923 }
3924
3925 /*
3926  * dumpPublicationTable
3927  *        dump the definition of the given publication table mapping
3928  */
3929 static void
3930 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
3931 {
3932         TableInfo  *tbinfo = pubrinfo->pubtable;
3933         PQExpBuffer query;
3934         char       *tag;
3935
3936         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3937                 return;
3938
3939         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
3940
3941         query = createPQExpBuffer();
3942
3943         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
3944                                           fmtId(pubrinfo->pubname));
3945         appendPQExpBuffer(query, " %s;\n",
3946                                           fmtQualifiedDumpable(tbinfo));
3947
3948         /*
3949          * There is no point in creating drop query as drop query as the drop is
3950          * done by table drop.
3951          */
3952         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
3953                                  tag,
3954                                  tbinfo->dobj.namespace->dobj.name,
3955                                  NULL,
3956                                  "",
3957                                  "PUBLICATION TABLE", SECTION_POST_DATA,
3958                                  query->data, "", NULL,
3959                                  NULL, 0,
3960                                  NULL, NULL);
3961
3962         free(tag);
3963         destroyPQExpBuffer(query);
3964 }
3965
3966 /*
3967  * Is the currently connected user a superuser?
3968  */
3969 static bool
3970 is_superuser(Archive *fout)
3971 {
3972         ArchiveHandle *AH = (ArchiveHandle *) fout;
3973         const char *val;
3974
3975         val = PQparameterStatus(AH->connection, "is_superuser");
3976
3977         if (val && strcmp(val, "on") == 0)
3978                 return true;
3979
3980         return false;
3981 }
3982
3983 /*
3984  * getSubscriptions
3985  *        get information about subscriptions
3986  */
3987 void
3988 getSubscriptions(Archive *fout)
3989 {
3990         DumpOptions *dopt = fout->dopt;
3991         PQExpBuffer query;
3992         PGresult   *res;
3993         SubscriptionInfo *subinfo;
3994         int                     i_tableoid;
3995         int                     i_oid;
3996         int                     i_subname;
3997         int                     i_rolname;
3998         int                     i_subconninfo;
3999         int                     i_subslotname;
4000         int                     i_subsynccommit;
4001         int                     i_subpublications;
4002         int                     i,
4003                                 ntups;
4004
4005         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4006                 return;
4007
4008         if (!is_superuser(fout))
4009         {
4010                 int                     n;
4011
4012                 res = ExecuteSqlQuery(fout,
4013                                                           "SELECT count(*) FROM pg_subscription "
4014                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4015                                                           "                 WHERE datname = current_database())",
4016                                                           PGRES_TUPLES_OK);
4017                 n = atoi(PQgetvalue(res, 0, 0));
4018                 if (n > 0)
4019                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4020                 PQclear(res);
4021                 return;
4022         }
4023
4024         query = createPQExpBuffer();
4025
4026         resetPQExpBuffer(query);
4027
4028         /* Get the subscriptions in current database. */
4029         appendPQExpBuffer(query,
4030                                           "SELECT s.tableoid, s.oid, s.subname,"
4031                                           "(%s s.subowner) AS rolname, "
4032                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4033                                           " s.subpublications "
4034                                           "FROM pg_subscription s "
4035                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4036                                           "                   WHERE datname = current_database())",
4037                                           username_subquery);
4038         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4039
4040         ntups = PQntuples(res);
4041
4042         i_tableoid = PQfnumber(res, "tableoid");
4043         i_oid = PQfnumber(res, "oid");
4044         i_subname = PQfnumber(res, "subname");
4045         i_rolname = PQfnumber(res, "rolname");
4046         i_subconninfo = PQfnumber(res, "subconninfo");
4047         i_subslotname = PQfnumber(res, "subslotname");
4048         i_subsynccommit = PQfnumber(res, "subsynccommit");
4049         i_subpublications = PQfnumber(res, "subpublications");
4050
4051         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4052
4053         for (i = 0; i < ntups; i++)
4054         {
4055                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4056                 subinfo[i].dobj.catId.tableoid =
4057                         atooid(PQgetvalue(res, i, i_tableoid));
4058                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4059                 AssignDumpId(&subinfo[i].dobj);
4060                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4061                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4062                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4063                 if (PQgetisnull(res, i, i_subslotname))
4064                         subinfo[i].subslotname = NULL;
4065                 else
4066                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4067                 subinfo[i].subsynccommit =
4068                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4069                 subinfo[i].subpublications =
4070                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4071
4072                 if (strlen(subinfo[i].rolname) == 0)
4073                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4074                                           subinfo[i].dobj.name);
4075
4076                 /* Decide whether we want to dump it */
4077                 selectDumpableObject(&(subinfo[i].dobj), fout);
4078         }
4079         PQclear(res);
4080
4081         destroyPQExpBuffer(query);
4082 }
4083
4084 /*
4085  * dumpSubscription
4086  *        dump the definition of the given subscription
4087  */
4088 static void
4089 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4090 {
4091         PQExpBuffer delq;
4092         PQExpBuffer query;
4093         PQExpBuffer publications;
4094         char       *qsubname;
4095         char      **pubnames = NULL;
4096         int                     npubnames = 0;
4097         int                     i;
4098
4099         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4100                 return;
4101
4102         delq = createPQExpBuffer();
4103         query = createPQExpBuffer();
4104
4105         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4106
4107         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4108                                           qsubname);
4109
4110         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4111                                           qsubname);
4112         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4113
4114         /* Build list of quoted publications and append them to query. */
4115         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4116         {
4117                 write_msg(NULL,
4118                                   "WARNING: could not parse subpublications array\n");
4119                 if (pubnames)
4120                         free(pubnames);
4121                 pubnames = NULL;
4122                 npubnames = 0;
4123         }
4124
4125         publications = createPQExpBuffer();
4126         for (i = 0; i < npubnames; i++)
4127         {
4128                 if (i > 0)
4129                         appendPQExpBufferStr(publications, ", ");
4130
4131                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4132         }
4133
4134         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4135         if (subinfo->subslotname)
4136                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4137         else
4138                 appendPQExpBufferStr(query, "NONE");
4139
4140         if (strcmp(subinfo->subsynccommit, "off") != 0)
4141                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4142
4143         appendPQExpBufferStr(query, ");\n");
4144
4145         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4146                                  subinfo->dobj.name,
4147                                  NULL,
4148                                  NULL,
4149                                  subinfo->rolname,
4150                                  "SUBSCRIPTION", SECTION_POST_DATA,
4151                                  query->data, delq->data, NULL,
4152                                  NULL, 0,
4153                                  NULL, NULL);
4154
4155         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4156                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4157                                         NULL, subinfo->rolname,
4158                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4159
4160         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4161                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4162                                          NULL, subinfo->rolname,
4163                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4164
4165         destroyPQExpBuffer(publications);
4166         if (pubnames)
4167                 free(pubnames);
4168
4169         destroyPQExpBuffer(delq);
4170         destroyPQExpBuffer(query);
4171         free(qsubname);
4172 }
4173
4174 static void
4175 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4176                                                                                  PQExpBuffer upgrade_buffer,
4177                                                                                  Oid pg_type_oid,
4178                                                                                  bool force_array_type)
4179 {
4180         PQExpBuffer upgrade_query = createPQExpBuffer();
4181         PGresult   *res;
4182         Oid                     pg_type_array_oid;
4183
4184         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4185         appendPQExpBuffer(upgrade_buffer,
4186                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4187                                           pg_type_oid);
4188
4189         /* we only support old >= 8.3 for binary upgrades */
4190         appendPQExpBuffer(upgrade_query,
4191                                           "SELECT typarray "
4192                                           "FROM pg_catalog.pg_type "
4193                                           "WHERE oid = '%u'::pg_catalog.oid;",
4194                                           pg_type_oid);
4195
4196         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4197
4198         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4199
4200         PQclear(res);
4201
4202         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4203         {
4204                 /*
4205                  * If the old version didn't assign an array type, but the new version
4206                  * does, we must select an unused type OID to assign.  This currently
4207                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4208                  *
4209                  * Note: local state here is kind of ugly, but we must have some,
4210                  * since we mustn't choose the same unused OID more than once.
4211                  */
4212                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4213                 bool            is_dup;
4214
4215                 do
4216                 {
4217                         ++next_possible_free_oid;
4218                         printfPQExpBuffer(upgrade_query,
4219                                                           "SELECT EXISTS(SELECT 1 "
4220                                                           "FROM pg_catalog.pg_type "
4221                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4222                                                           next_possible_free_oid);
4223                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4224                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4225                         PQclear(res);
4226                 } while (is_dup);
4227
4228                 pg_type_array_oid = next_possible_free_oid;
4229         }
4230
4231         if (OidIsValid(pg_type_array_oid))
4232         {
4233                 appendPQExpBufferStr(upgrade_buffer,
4234                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4235                 appendPQExpBuffer(upgrade_buffer,
4236                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4237                                                   pg_type_array_oid);
4238         }
4239
4240         destroyPQExpBuffer(upgrade_query);
4241 }
4242
4243 static bool
4244 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4245                                                                                 PQExpBuffer upgrade_buffer,
4246                                                                                 Oid pg_rel_oid)
4247 {
4248         PQExpBuffer upgrade_query = createPQExpBuffer();
4249         PGresult   *upgrade_res;
4250         Oid                     pg_type_oid;
4251         bool            toast_set = false;
4252
4253         /* we only support old >= 8.3 for binary upgrades */
4254         appendPQExpBuffer(upgrade_query,
4255                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4256                                           "FROM pg_catalog.pg_class c "
4257                                           "LEFT JOIN pg_catalog.pg_class t ON "
4258                                           "  (c.reltoastrelid = t.oid) "
4259                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4260                                           pg_rel_oid);
4261
4262         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4263
4264         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4265
4266         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4267                                                                                          pg_type_oid, false);
4268
4269         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4270         {
4271                 /* Toast tables do not have pg_type array rows */
4272                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4273                                                                                                                   PQfnumber(upgrade_res, "trel")));
4274
4275                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4276                 appendPQExpBuffer(upgrade_buffer,
4277                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4278                                                   pg_type_toast_oid);
4279
4280                 toast_set = true;
4281         }
4282
4283         PQclear(upgrade_res);
4284         destroyPQExpBuffer(upgrade_query);
4285
4286         return toast_set;
4287 }
4288
4289 static void
4290 binary_upgrade_set_pg_class_oids(Archive *fout,
4291                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4292                                                                  bool is_index)
4293 {
4294         PQExpBuffer upgrade_query = createPQExpBuffer();
4295         PGresult   *upgrade_res;
4296         Oid                     pg_class_reltoastrelid;
4297         Oid                     pg_index_indexrelid;
4298
4299         appendPQExpBuffer(upgrade_query,
4300                                           "SELECT c.reltoastrelid, i.indexrelid "
4301                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4302                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4303                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4304                                           pg_class_oid);
4305
4306         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4307
4308         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4309         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4310
4311         appendPQExpBufferStr(upgrade_buffer,
4312                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4313
4314         if (!is_index)
4315         {
4316                 appendPQExpBuffer(upgrade_buffer,
4317                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4318                                                   pg_class_oid);
4319                 /* only tables have toast tables, not indexes */
4320                 if (OidIsValid(pg_class_reltoastrelid))
4321                 {
4322                         /*
4323                          * One complexity is that the table definition might not require
4324                          * the creation of a TOAST table, and the TOAST table might have
4325                          * been created long after table creation, when the table was
4326                          * loaded with wide data.  By setting the TOAST oid we force
4327                          * creation of the TOAST heap and TOAST index by the backend so we
4328                          * can cleanly copy the files during binary upgrade.
4329                          */
4330
4331                         appendPQExpBuffer(upgrade_buffer,
4332                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4333                                                           pg_class_reltoastrelid);
4334
4335                         /* every toast table has an index */
4336                         appendPQExpBuffer(upgrade_buffer,
4337                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4338                                                           pg_index_indexrelid);
4339                 }
4340         }
4341         else
4342                 appendPQExpBuffer(upgrade_buffer,
4343                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4344                                                   pg_class_oid);
4345
4346         appendPQExpBufferChar(upgrade_buffer, '\n');
4347
4348         PQclear(upgrade_res);
4349         destroyPQExpBuffer(upgrade_query);
4350 }
4351
4352 /*
4353  * If the DumpableObject is a member of an extension, add a suitable
4354  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4355  *
4356  * For somewhat historical reasons, objname should already be quoted,
4357  * but not objnamespace (if any).
4358  */
4359 static void
4360 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4361                                                                 DumpableObject *dobj,
4362                                                                 const char *objtype,
4363                                                                 const char *objname,
4364                                                                 const char *objnamespace)
4365 {
4366         DumpableObject *extobj = NULL;
4367         int                     i;
4368
4369         if (!dobj->ext_member)
4370                 return;
4371
4372         /*
4373          * Find the parent extension.  We could avoid this search if we wanted to
4374          * add a link field to DumpableObject, but the space costs of that would
4375          * be considerable.  We assume that member objects could only have a
4376          * direct dependency on their own extension, not any others.
4377          */
4378         for (i = 0; i < dobj->nDeps; i++)
4379         {
4380                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4381                 if (extobj && extobj->objType == DO_EXTENSION)
4382                         break;
4383                 extobj = NULL;
4384         }
4385         if (extobj == NULL)
4386                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4387                                           objtype, objname);
4388
4389         appendPQExpBufferStr(upgrade_buffer,
4390                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4391         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4392                                           fmtId(extobj->name),
4393                                           objtype);
4394         if (objnamespace && *objnamespace)
4395                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4396         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4397 }
4398
4399 /*
4400  * getNamespaces:
4401  *        read all namespaces in the system catalogs and return them in the
4402  * NamespaceInfo* structure
4403  *
4404  *      numNamespaces is set to the number of namespaces read in
4405  */
4406 NamespaceInfo *
4407 getNamespaces(Archive *fout, int *numNamespaces)
4408 {
4409         DumpOptions *dopt = fout->dopt;
4410         PGresult   *res;
4411         int                     ntups;
4412         int                     i;
4413         PQExpBuffer query;
4414         NamespaceInfo *nsinfo;
4415         int                     i_tableoid;
4416         int                     i_oid;
4417         int                     i_nspname;
4418         int                     i_rolname;
4419         int                     i_nspacl;
4420         int                     i_rnspacl;
4421         int                     i_initnspacl;
4422         int                     i_initrnspacl;
4423
4424         query = createPQExpBuffer();
4425
4426         /*
4427          * we fetch all namespaces including system ones, so that every object we
4428          * read in can be linked to a containing namespace.
4429          */
4430         if (fout->remoteVersion >= 90600)
4431         {
4432                 PQExpBuffer acl_subquery = createPQExpBuffer();
4433                 PQExpBuffer racl_subquery = createPQExpBuffer();
4434                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4435                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4436
4437                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4438                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4439                                                 dopt->binary_upgrade);
4440
4441                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4442                                                   "(%s nspowner) AS rolname, "
4443                                                   "%s as nspacl, "
4444                                                   "%s as rnspacl, "
4445                                                   "%s as initnspacl, "
4446                                                   "%s as initrnspacl "
4447                                                   "FROM pg_namespace n "
4448                                                   "LEFT JOIN pg_init_privs pip "
4449                                                   "ON (n.oid = pip.objoid "
4450                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4451                                                   "AND pip.objsubid = 0",
4452                                                   username_subquery,
4453                                                   acl_subquery->data,
4454                                                   racl_subquery->data,
4455                                                   init_acl_subquery->data,
4456                                                   init_racl_subquery->data);
4457
4458                 appendPQExpBuffer(query, ") ");
4459
4460                 destroyPQExpBuffer(acl_subquery);
4461                 destroyPQExpBuffer(racl_subquery);
4462                 destroyPQExpBuffer(init_acl_subquery);
4463                 destroyPQExpBuffer(init_racl_subquery);
4464         }
4465         else
4466                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4467                                                   "(%s nspowner) AS rolname, "
4468                                                   "nspacl, NULL as rnspacl, "
4469                                                   "NULL AS initnspacl, NULL as initrnspacl "
4470                                                   "FROM pg_namespace",
4471                                                   username_subquery);
4472
4473         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4474
4475         ntups = PQntuples(res);
4476
4477         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4478
4479         i_tableoid = PQfnumber(res, "tableoid");
4480         i_oid = PQfnumber(res, "oid");
4481         i_nspname = PQfnumber(res, "nspname");
4482         i_rolname = PQfnumber(res, "rolname");
4483         i_nspacl = PQfnumber(res, "nspacl");
4484         i_rnspacl = PQfnumber(res, "rnspacl");
4485         i_initnspacl = PQfnumber(res, "initnspacl");
4486         i_initrnspacl = PQfnumber(res, "initrnspacl");
4487
4488         for (i = 0; i < ntups; i++)
4489         {
4490                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4491                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4492                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4493                 AssignDumpId(&nsinfo[i].dobj);
4494                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4495                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4496                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4497                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4498                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4499                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4500
4501                 /* Decide whether to dump this namespace */
4502                 selectDumpableNamespace(&nsinfo[i], fout);
4503
4504                 /*
4505                  * Do not try to dump ACL if the ACL is empty or the default.
4506                  *
4507                  * This is useful because, for some schemas/objects, the only
4508                  * component we are going to try and dump is the ACL and if we can
4509                  * remove that then 'dump' goes to zero/false and we don't consider
4510                  * this object for dumping at all later on.
4511                  */
4512                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4513                         PQgetisnull(res, i, i_initnspacl) &&
4514                         PQgetisnull(res, i, i_initrnspacl))
4515                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4516
4517                 if (strlen(nsinfo[i].rolname) == 0)
4518                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4519                                           nsinfo[i].dobj.name);
4520         }
4521
4522         PQclear(res);
4523         destroyPQExpBuffer(query);
4524
4525         *numNamespaces = ntups;
4526
4527         return nsinfo;
4528 }
4529
4530 /*
4531  * findNamespace:
4532  *              given a namespace OID, look up the info read by getNamespaces
4533  */
4534 static NamespaceInfo *
4535 findNamespace(Archive *fout, Oid nsoid)
4536 {
4537         NamespaceInfo *nsinfo;
4538
4539         nsinfo = findNamespaceByOid(nsoid);
4540         if (nsinfo == NULL)
4541                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4542         return nsinfo;
4543 }
4544
4545 /*
4546  * getExtensions:
4547  *        read all extensions in the system catalogs and return them in the
4548  * ExtensionInfo* structure
4549  *
4550  *      numExtensions is set to the number of extensions read in
4551  */
4552 ExtensionInfo *
4553 getExtensions(Archive *fout, int *numExtensions)
4554 {
4555         DumpOptions *dopt = fout->dopt;
4556         PGresult   *res;
4557         int                     ntups;
4558         int                     i;
4559         PQExpBuffer query;
4560         ExtensionInfo *extinfo;
4561         int                     i_tableoid;
4562         int                     i_oid;
4563         int                     i_extname;
4564         int                     i_nspname;
4565         int                     i_extrelocatable;
4566         int                     i_extversion;
4567         int                     i_extconfig;
4568         int                     i_extcondition;
4569
4570         /*
4571          * Before 9.1, there are no extensions.
4572          */
4573         if (fout->remoteVersion < 90100)
4574         {
4575                 *numExtensions = 0;
4576                 return NULL;
4577         }
4578
4579         query = createPQExpBuffer();
4580
4581         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4582                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4583                                                  "FROM pg_extension x "
4584                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4585
4586         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4587
4588         ntups = PQntuples(res);
4589
4590         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4591
4592         i_tableoid = PQfnumber(res, "tableoid");
4593         i_oid = PQfnumber(res, "oid");
4594         i_extname = PQfnumber(res, "extname");
4595         i_nspname = PQfnumber(res, "nspname");
4596         i_extrelocatable = PQfnumber(res, "extrelocatable");
4597         i_extversion = PQfnumber(res, "extversion");
4598         i_extconfig = PQfnumber(res, "extconfig");
4599         i_extcondition = PQfnumber(res, "extcondition");
4600
4601         for (i = 0; i < ntups; i++)
4602         {
4603                 extinfo[i].dobj.objType = DO_EXTENSION;
4604                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4605                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4606                 AssignDumpId(&extinfo[i].dobj);
4607                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4608                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4609                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4610                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4611                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4612                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4613
4614                 /* Decide whether we want to dump it */
4615                 selectDumpableExtension(&(extinfo[i]), dopt);
4616         }
4617
4618         PQclear(res);
4619         destroyPQExpBuffer(query);
4620
4621         *numExtensions = ntups;
4622
4623         return extinfo;
4624 }
4625
4626 /*
4627  * getTypes:
4628  *        read all types in the system catalogs and return them in the
4629  * TypeInfo* structure
4630  *
4631  *      numTypes is set to the number of types read in
4632  *
4633  * NB: this must run after getFuncs() because we assume we can do
4634  * findFuncByOid().
4635  */
4636 TypeInfo *
4637 getTypes(Archive *fout, int *numTypes)
4638 {
4639         DumpOptions *dopt = fout->dopt;
4640         PGresult   *res;
4641         int                     ntups;
4642         int                     i;
4643         PQExpBuffer query = createPQExpBuffer();
4644         TypeInfo   *tyinfo;
4645         ShellTypeInfo *stinfo;
4646         int                     i_tableoid;
4647         int                     i_oid;
4648         int                     i_typname;
4649         int                     i_typnamespace;
4650         int                     i_typacl;
4651         int                     i_rtypacl;
4652         int                     i_inittypacl;
4653         int                     i_initrtypacl;
4654         int                     i_rolname;
4655         int                     i_typelem;
4656         int                     i_typrelid;
4657         int                     i_typrelkind;
4658         int                     i_typtype;
4659         int                     i_typisdefined;
4660         int                     i_isarray;
4661
4662         /*
4663          * we include even the built-in types because those may be used as array
4664          * elements by user-defined types
4665          *
4666          * we filter out the built-in types when we dump out the types
4667          *
4668          * same approach for undefined (shell) types and array types
4669          *
4670          * Note: as of 8.3 we can reliably detect whether a type is an
4671          * auto-generated array type by checking the element type's typarray.
4672          * (Before that the test is capable of generating false positives.) We
4673          * still check for name beginning with '_', though, so as to avoid the
4674          * cost of the subselect probe for all standard types.  This would have to
4675          * be revisited if the backend ever allows renaming of array types.
4676          */
4677
4678         if (fout->remoteVersion >= 90600)
4679         {
4680                 PQExpBuffer acl_subquery = createPQExpBuffer();
4681                 PQExpBuffer racl_subquery = createPQExpBuffer();
4682                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4683                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4684
4685                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4686                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4687                                                 dopt->binary_upgrade);
4688
4689                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4690                                                   "t.typnamespace, "
4691                                                   "%s AS typacl, "
4692                                                   "%s AS rtypacl, "
4693                                                   "%s AS inittypacl, "
4694                                                   "%s AS initrtypacl, "
4695                                                   "(%s t.typowner) AS rolname, "
4696                                                   "t.typelem, t.typrelid, "
4697                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4698                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4699                                                   "t.typtype, t.typisdefined, "
4700                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4701                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4702                                                   "FROM pg_type t "
4703                                                   "LEFT JOIN pg_init_privs pip ON "
4704                                                   "(t.oid = pip.objoid "
4705                                                   "AND pip.classoid = 'pg_type'::regclass "
4706                                                   "AND pip.objsubid = 0) ",
4707                                                   acl_subquery->data,
4708                                                   racl_subquery->data,
4709                                                   initacl_subquery->data,
4710                                                   initracl_subquery->data,
4711                                                   username_subquery);
4712
4713                 destroyPQExpBuffer(acl_subquery);
4714                 destroyPQExpBuffer(racl_subquery);
4715                 destroyPQExpBuffer(initacl_subquery);
4716                 destroyPQExpBuffer(initracl_subquery);
4717         }
4718         else if (fout->remoteVersion >= 90200)
4719         {
4720                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4721                                                   "typnamespace, typacl, NULL as rtypacl, "
4722                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4723                                                   "(%s typowner) AS rolname, "
4724                                                   "typelem, typrelid, "
4725                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4726                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4727                                                   "typtype, typisdefined, "
4728                                                   "typname[0] = '_' AND typelem != 0 AND "
4729                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4730                                                   "FROM pg_type",
4731                                                   username_subquery);
4732         }
4733         else if (fout->remoteVersion >= 80300)
4734         {
4735                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4736                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4737                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4738                                                   "(%s typowner) AS rolname, "
4739                                                   "typelem, typrelid, "
4740                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4741                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4742                                                   "typtype, typisdefined, "
4743                                                   "typname[0] = '_' AND typelem != 0 AND "
4744                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4745                                                   "FROM pg_type",
4746                                                   username_subquery);
4747         }
4748         else
4749         {
4750                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4751                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4752                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4753                                                   "(%s typowner) AS rolname, "
4754                                                   "typelem, typrelid, "
4755                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4756                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4757                                                   "typtype, typisdefined, "
4758                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4759                                                   "FROM pg_type",
4760                                                   username_subquery);
4761         }
4762
4763         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4764
4765         ntups = PQntuples(res);
4766
4767         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4768
4769         i_tableoid = PQfnumber(res, "tableoid");
4770         i_oid = PQfnumber(res, "oid");
4771         i_typname = PQfnumber(res, "typname");
4772         i_typnamespace = PQfnumber(res, "typnamespace");
4773         i_typacl = PQfnumber(res, "typacl");
4774         i_rtypacl = PQfnumber(res, "rtypacl");
4775         i_inittypacl = PQfnumber(res, "inittypacl");
4776         i_initrtypacl = PQfnumber(res, "initrtypacl");
4777         i_rolname = PQfnumber(res, "rolname");
4778         i_typelem = PQfnumber(res, "typelem");
4779         i_typrelid = PQfnumber(res, "typrelid");
4780         i_typrelkind = PQfnumber(res, "typrelkind");
4781         i_typtype = PQfnumber(res, "typtype");
4782         i_typisdefined = PQfnumber(res, "typisdefined");
4783         i_isarray = PQfnumber(res, "isarray");
4784
4785         for (i = 0; i < ntups; i++)
4786         {
4787                 tyinfo[i].dobj.objType = DO_TYPE;
4788                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4789                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4790                 AssignDumpId(&tyinfo[i].dobj);
4791                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4792                 tyinfo[i].dobj.namespace =
4793                         findNamespace(fout,
4794                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4795                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4796                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4797                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4798                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4799                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4800                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4801                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4802                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4803                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4804                 tyinfo[i].shellType = NULL;
4805
4806                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4807                         tyinfo[i].isDefined = true;
4808                 else
4809                         tyinfo[i].isDefined = false;
4810
4811                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4812                         tyinfo[i].isArray = true;
4813                 else
4814                         tyinfo[i].isArray = false;
4815
4816                 /* Decide whether we want to dump it */
4817                 selectDumpableType(&tyinfo[i], fout);
4818
4819                 /* Do not try to dump ACL if no ACL exists. */
4820                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4821                         PQgetisnull(res, i, i_inittypacl) &&
4822                         PQgetisnull(res, i, i_initrtypacl))
4823                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4824
4825                 /*
4826                  * If it's a domain, fetch info about its constraints, if any
4827                  */
4828                 tyinfo[i].nDomChecks = 0;
4829                 tyinfo[i].domChecks = NULL;
4830                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4831                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4832                         getDomainConstraints(fout, &(tyinfo[i]));
4833
4834                 /*
4835                  * If it's a base type, make a DumpableObject representing a shell
4836                  * definition of the type.  We will need to dump that ahead of the I/O
4837                  * functions for the type.  Similarly, range types need a shell
4838                  * definition in case they have a canonicalize function.
4839                  *
4840                  * Note: the shell type doesn't have a catId.  You might think it
4841                  * should copy the base type's catId, but then it might capture the
4842                  * pg_depend entries for the type, which we don't want.
4843                  */
4844                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4845                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4846                          tyinfo[i].typtype == TYPTYPE_RANGE))
4847                 {
4848                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4849                         stinfo->dobj.objType = DO_SHELL_TYPE;
4850                         stinfo->dobj.catId = nilCatalogId;
4851                         AssignDumpId(&stinfo->dobj);
4852                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4853                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4854                         stinfo->baseType = &(tyinfo[i]);
4855                         tyinfo[i].shellType = stinfo;
4856
4857                         /*
4858                          * Initially mark the shell type as not to be dumped.  We'll only
4859                          * dump it if the I/O or canonicalize functions need to be dumped;
4860                          * this is taken care of while sorting dependencies.
4861                          */
4862                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4863                 }
4864
4865                 if (strlen(tyinfo[i].rolname) == 0)
4866                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4867                                           tyinfo[i].dobj.name);
4868         }
4869
4870         *numTypes = ntups;
4871
4872         PQclear(res);
4873
4874         destroyPQExpBuffer(query);
4875
4876         return tyinfo;
4877 }
4878
4879 /*
4880  * getOperators:
4881  *        read all operators in the system catalogs and return them in the
4882  * OprInfo* structure
4883  *
4884  *      numOprs is set to the number of operators read in
4885  */
4886 OprInfo *
4887 getOperators(Archive *fout, int *numOprs)
4888 {
4889         PGresult   *res;
4890         int                     ntups;
4891         int                     i;
4892         PQExpBuffer query = createPQExpBuffer();
4893         OprInfo    *oprinfo;
4894         int                     i_tableoid;
4895         int                     i_oid;
4896         int                     i_oprname;
4897         int                     i_oprnamespace;
4898         int                     i_rolname;
4899         int                     i_oprkind;
4900         int                     i_oprcode;
4901
4902         /*
4903          * find all operators, including builtin operators; we filter out
4904          * system-defined operators at dump-out time.
4905          */
4906
4907         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4908                                           "oprnamespace, "
4909                                           "(%s oprowner) AS rolname, "
4910                                           "oprkind, "
4911                                           "oprcode::oid AS oprcode "
4912                                           "FROM pg_operator",
4913                                           username_subquery);
4914
4915         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4916
4917         ntups = PQntuples(res);
4918         *numOprs = ntups;
4919
4920         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4921
4922         i_tableoid = PQfnumber(res, "tableoid");
4923         i_oid = PQfnumber(res, "oid");
4924         i_oprname = PQfnumber(res, "oprname");
4925         i_oprnamespace = PQfnumber(res, "oprnamespace");
4926         i_rolname = PQfnumber(res, "rolname");
4927         i_oprkind = PQfnumber(res, "oprkind");
4928         i_oprcode = PQfnumber(res, "oprcode");
4929
4930         for (i = 0; i < ntups; i++)
4931         {
4932                 oprinfo[i].dobj.objType = DO_OPERATOR;
4933                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4934                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4935                 AssignDumpId(&oprinfo[i].dobj);
4936                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4937                 oprinfo[i].dobj.namespace =
4938                         findNamespace(fout,
4939                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
4940                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4941                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4942                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4943
4944                 /* Decide whether we want to dump it */
4945                 selectDumpableObject(&(oprinfo[i].dobj), fout);
4946
4947                 /* Operators do not currently have ACLs. */
4948                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4949
4950                 if (strlen(oprinfo[i].rolname) == 0)
4951                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4952                                           oprinfo[i].dobj.name);
4953         }
4954
4955         PQclear(res);
4956
4957         destroyPQExpBuffer(query);
4958
4959         return oprinfo;
4960 }
4961
4962 /*
4963  * getCollations:
4964  *        read all collations in the system catalogs and return them in the
4965  * CollInfo* structure
4966  *
4967  *      numCollations is set to the number of collations read in
4968  */
4969 CollInfo *
4970 getCollations(Archive *fout, int *numCollations)
4971 {
4972         PGresult   *res;
4973         int                     ntups;
4974         int                     i;
4975         PQExpBuffer query;
4976         CollInfo   *collinfo;
4977         int                     i_tableoid;
4978         int                     i_oid;
4979         int                     i_collname;
4980         int                     i_collnamespace;
4981         int                     i_rolname;
4982
4983         /* Collations didn't exist pre-9.1 */
4984         if (fout->remoteVersion < 90100)
4985         {
4986                 *numCollations = 0;
4987                 return NULL;
4988         }
4989
4990         query = createPQExpBuffer();
4991
4992         /*
4993          * find all collations, including builtin collations; we filter out
4994          * system-defined collations at dump-out time.
4995          */
4996
4997         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
4998                                           "collnamespace, "
4999                                           "(%s collowner) AS rolname "
5000                                           "FROM pg_collation",
5001                                           username_subquery);
5002
5003         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5004
5005         ntups = PQntuples(res);
5006         *numCollations = ntups;
5007
5008         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5009
5010         i_tableoid = PQfnumber(res, "tableoid");
5011         i_oid = PQfnumber(res, "oid");
5012         i_collname = PQfnumber(res, "collname");
5013         i_collnamespace = PQfnumber(res, "collnamespace");
5014         i_rolname = PQfnumber(res, "rolname");
5015
5016         for (i = 0; i < ntups; i++)
5017         {
5018                 collinfo[i].dobj.objType = DO_COLLATION;
5019                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5020                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5021                 AssignDumpId(&collinfo[i].dobj);
5022                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5023                 collinfo[i].dobj.namespace =
5024                         findNamespace(fout,
5025                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5026                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5027
5028                 /* Decide whether we want to dump it */
5029                 selectDumpableObject(&(collinfo[i].dobj), fout);
5030
5031                 /* Collations do not currently have ACLs. */
5032                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5033         }
5034
5035         PQclear(res);
5036
5037         destroyPQExpBuffer(query);
5038
5039         return collinfo;
5040 }
5041
5042 /*
5043  * getConversions:
5044  *        read all conversions in the system catalogs and return them in the
5045  * ConvInfo* structure
5046  *
5047  *      numConversions is set to the number of conversions read in
5048  */
5049 ConvInfo *
5050 getConversions(Archive *fout, int *numConversions)
5051 {
5052         PGresult   *res;
5053         int                     ntups;
5054         int                     i;
5055         PQExpBuffer query;
5056         ConvInfo   *convinfo;
5057         int                     i_tableoid;
5058         int                     i_oid;
5059         int                     i_conname;
5060         int                     i_connamespace;
5061         int                     i_rolname;
5062
5063         query = createPQExpBuffer();
5064
5065         /*
5066          * find all conversions, including builtin conversions; we filter out
5067          * system-defined conversions at dump-out time.
5068          */
5069
5070         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5071                                           "connamespace, "
5072                                           "(%s conowner) AS rolname "
5073                                           "FROM pg_conversion",
5074                                           username_subquery);
5075
5076         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5077
5078         ntups = PQntuples(res);
5079         *numConversions = ntups;
5080
5081         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5082
5083         i_tableoid = PQfnumber(res, "tableoid");
5084         i_oid = PQfnumber(res, "oid");
5085         i_conname = PQfnumber(res, "conname");
5086         i_connamespace = PQfnumber(res, "connamespace");
5087         i_rolname = PQfnumber(res, "rolname");
5088
5089         for (i = 0; i < ntups; i++)
5090         {
5091                 convinfo[i].dobj.objType = DO_CONVERSION;
5092                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5093                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5094                 AssignDumpId(&convinfo[i].dobj);
5095                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5096                 convinfo[i].dobj.namespace =
5097                         findNamespace(fout,
5098                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5099                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5100
5101                 /* Decide whether we want to dump it */
5102                 selectDumpableObject(&(convinfo[i].dobj), fout);
5103
5104                 /* Conversions do not currently have ACLs. */
5105                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5106         }
5107
5108         PQclear(res);
5109
5110         destroyPQExpBuffer(query);
5111
5112         return convinfo;
5113 }
5114
5115 /*
5116  * getAccessMethods:
5117  *        read all user-defined access methods in the system catalogs and return
5118  *        them in the AccessMethodInfo* structure
5119  *
5120  *      numAccessMethods is set to the number of access methods read in
5121  */
5122 AccessMethodInfo *
5123 getAccessMethods(Archive *fout, int *numAccessMethods)
5124 {
5125         PGresult   *res;
5126         int                     ntups;
5127         int                     i;
5128         PQExpBuffer query;
5129         AccessMethodInfo *aminfo;
5130         int                     i_tableoid;
5131         int                     i_oid;
5132         int                     i_amname;
5133         int                     i_amhandler;
5134         int                     i_amtype;
5135
5136         /* Before 9.6, there are no user-defined access methods */
5137         if (fout->remoteVersion < 90600)
5138         {
5139                 *numAccessMethods = 0;
5140                 return NULL;
5141         }
5142
5143         query = createPQExpBuffer();
5144
5145         /* Select all access methods from pg_am table */
5146         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5147                                           "amhandler::pg_catalog.regproc AS amhandler "
5148                                           "FROM pg_am");
5149
5150         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5151
5152         ntups = PQntuples(res);
5153         *numAccessMethods = ntups;
5154
5155         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5156
5157         i_tableoid = PQfnumber(res, "tableoid");
5158         i_oid = PQfnumber(res, "oid");
5159         i_amname = PQfnumber(res, "amname");
5160         i_amhandler = PQfnumber(res, "amhandler");
5161         i_amtype = PQfnumber(res, "amtype");
5162
5163         for (i = 0; i < ntups; i++)
5164         {
5165                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5166                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5167                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5168                 AssignDumpId(&aminfo[i].dobj);
5169                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5170                 aminfo[i].dobj.namespace = NULL;
5171                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5172                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5173
5174                 /* Decide whether we want to dump it */
5175                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5176
5177                 /* Access methods do not currently have ACLs. */
5178                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5179         }
5180
5181         PQclear(res);
5182
5183         destroyPQExpBuffer(query);
5184
5185         return aminfo;
5186 }
5187
5188
5189 /*
5190  * getOpclasses:
5191  *        read all opclasses in the system catalogs and return them in the
5192  * OpclassInfo* structure
5193  *
5194  *      numOpclasses is set to the number of opclasses read in
5195  */
5196 OpclassInfo *
5197 getOpclasses(Archive *fout, int *numOpclasses)
5198 {
5199         PGresult   *res;
5200         int                     ntups;
5201         int                     i;
5202         PQExpBuffer query = createPQExpBuffer();
5203         OpclassInfo *opcinfo;
5204         int                     i_tableoid;
5205         int                     i_oid;
5206         int                     i_opcname;
5207         int                     i_opcnamespace;
5208         int                     i_rolname;
5209
5210         /*
5211          * find all opclasses, including builtin opclasses; we filter out
5212          * system-defined opclasses at dump-out time.
5213          */
5214
5215         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5216                                           "opcnamespace, "
5217                                           "(%s opcowner) AS rolname "
5218                                           "FROM pg_opclass",
5219                                           username_subquery);
5220
5221         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5222
5223         ntups = PQntuples(res);
5224         *numOpclasses = ntups;
5225
5226         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5227
5228         i_tableoid = PQfnumber(res, "tableoid");
5229         i_oid = PQfnumber(res, "oid");
5230         i_opcname = PQfnumber(res, "opcname");
5231         i_opcnamespace = PQfnumber(res, "opcnamespace");
5232         i_rolname = PQfnumber(res, "rolname");
5233
5234         for (i = 0; i < ntups; i++)
5235         {
5236                 opcinfo[i].dobj.objType = DO_OPCLASS;
5237                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5238                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5239                 AssignDumpId(&opcinfo[i].dobj);
5240                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5241                 opcinfo[i].dobj.namespace =
5242                         findNamespace(fout,
5243                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5244                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5245
5246                 /* Decide whether we want to dump it */
5247                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5248
5249                 /* Op Classes do not currently have ACLs. */
5250                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5251
5252                 if (strlen(opcinfo[i].rolname) == 0)
5253                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5254                                           opcinfo[i].dobj.name);
5255         }
5256
5257         PQclear(res);
5258
5259         destroyPQExpBuffer(query);
5260
5261         return opcinfo;
5262 }
5263
5264 /*
5265  * getOpfamilies:
5266  *        read all opfamilies in the system catalogs and return them in the
5267  * OpfamilyInfo* structure
5268  *
5269  *      numOpfamilies is set to the number of opfamilies read in
5270  */
5271 OpfamilyInfo *
5272 getOpfamilies(Archive *fout, int *numOpfamilies)
5273 {
5274         PGresult   *res;
5275         int                     ntups;
5276         int                     i;
5277         PQExpBuffer query;
5278         OpfamilyInfo *opfinfo;
5279         int                     i_tableoid;
5280         int                     i_oid;
5281         int                     i_opfname;
5282         int                     i_opfnamespace;
5283         int                     i_rolname;
5284
5285         /* Before 8.3, there is no separate concept of opfamilies */
5286         if (fout->remoteVersion < 80300)
5287         {
5288                 *numOpfamilies = 0;
5289                 return NULL;
5290         }
5291
5292         query = createPQExpBuffer();
5293
5294         /*
5295          * find all opfamilies, including builtin opfamilies; we filter out
5296          * system-defined opfamilies at dump-out time.
5297          */
5298
5299         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5300                                           "opfnamespace, "
5301                                           "(%s opfowner) AS rolname "
5302                                           "FROM pg_opfamily",
5303                                           username_subquery);
5304
5305         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5306
5307         ntups = PQntuples(res);
5308         *numOpfamilies = ntups;
5309
5310         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5311
5312         i_tableoid = PQfnumber(res, "tableoid");
5313         i_oid = PQfnumber(res, "oid");
5314         i_opfname = PQfnumber(res, "opfname");
5315         i_opfnamespace = PQfnumber(res, "opfnamespace");
5316         i_rolname = PQfnumber(res, "rolname");
5317
5318         for (i = 0; i < ntups; i++)
5319         {
5320                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5321                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5322                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5323                 AssignDumpId(&opfinfo[i].dobj);
5324                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5325                 opfinfo[i].dobj.namespace =
5326                         findNamespace(fout,
5327                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5328                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5329
5330                 /* Decide whether we want to dump it */
5331                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5332
5333                 /* Extensions do not currently have ACLs. */
5334                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5335
5336                 if (strlen(opfinfo[i].rolname) == 0)
5337                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5338                                           opfinfo[i].dobj.name);
5339         }
5340
5341         PQclear(res);
5342
5343         destroyPQExpBuffer(query);
5344
5345         return opfinfo;
5346 }
5347
5348 /*
5349  * getAggregates:
5350  *        read all the user-defined aggregates in the system catalogs and
5351  * return them in the AggInfo* structure
5352  *
5353  * numAggs is set to the number of aggregates read in
5354  */
5355 AggInfo *
5356 getAggregates(Archive *fout, int *numAggs)
5357 {
5358         DumpOptions *dopt = fout->dopt;
5359         PGresult   *res;
5360         int                     ntups;
5361         int                     i;
5362         PQExpBuffer query = createPQExpBuffer();
5363         AggInfo    *agginfo;
5364         int                     i_tableoid;
5365         int                     i_oid;
5366         int                     i_aggname;
5367         int                     i_aggnamespace;
5368         int                     i_pronargs;
5369         int                     i_proargtypes;
5370         int                     i_rolname;
5371         int                     i_aggacl;
5372         int                     i_raggacl;
5373         int                     i_initaggacl;
5374         int                     i_initraggacl;
5375
5376         /*
5377          * Find all interesting aggregates.  See comment in getFuncs() for the
5378          * rationale behind the filtering logic.
5379          */
5380         if (fout->remoteVersion >= 90600)
5381         {
5382                 PQExpBuffer acl_subquery = createPQExpBuffer();
5383                 PQExpBuffer racl_subquery = createPQExpBuffer();
5384                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5385                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5386                 const char *agg_check;
5387
5388                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5389                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5390                                                 dopt->binary_upgrade);
5391
5392                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5393                                          : "p.proisagg");
5394
5395                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5396                                                   "p.proname AS aggname, "
5397                                                   "p.pronamespace AS aggnamespace, "
5398                                                   "p.pronargs, p.proargtypes, "
5399                                                   "(%s p.proowner) AS rolname, "
5400                                                   "%s AS aggacl, "
5401                                                   "%s AS raggacl, "
5402                                                   "%s AS initaggacl, "
5403                                                   "%s AS initraggacl "
5404                                                   "FROM pg_proc p "
5405                                                   "LEFT JOIN pg_init_privs pip ON "
5406                                                   "(p.oid = pip.objoid "
5407                                                   "AND pip.classoid = 'pg_proc'::regclass "
5408                                                   "AND pip.objsubid = 0) "
5409                                                   "WHERE %s AND ("
5410                                                   "p.pronamespace != "
5411                                                   "(SELECT oid FROM pg_namespace "
5412                                                   "WHERE nspname = 'pg_catalog') OR "
5413                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5414                                                   username_subquery,
5415                                                   acl_subquery->data,
5416                                                   racl_subquery->data,
5417                                                   initacl_subquery->data,
5418                                                   initracl_subquery->data,
5419                                                   agg_check);
5420                 if (dopt->binary_upgrade)
5421                         appendPQExpBufferStr(query,
5422                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5423                                                                  "classid = 'pg_proc'::regclass AND "
5424                                                                  "objid = p.oid AND "
5425                                                                  "refclassid = 'pg_extension'::regclass AND "
5426                                                                  "deptype = 'e')");
5427                 appendPQExpBufferChar(query, ')');
5428
5429                 destroyPQExpBuffer(acl_subquery);
5430                 destroyPQExpBuffer(racl_subquery);
5431                 destroyPQExpBuffer(initacl_subquery);
5432                 destroyPQExpBuffer(initracl_subquery);
5433         }
5434         else if (fout->remoteVersion >= 80200)
5435         {
5436                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5437                                                   "pronamespace AS aggnamespace, "
5438                                                   "pronargs, proargtypes, "
5439                                                   "(%s proowner) AS rolname, "
5440                                                   "proacl AS aggacl, "
5441                                                   "NULL AS raggacl, "
5442                                                   "NULL AS initaggacl, NULL AS initraggacl "
5443                                                   "FROM pg_proc p "
5444                                                   "WHERE proisagg AND ("
5445                                                   "pronamespace != "
5446                                                   "(SELECT oid FROM pg_namespace "
5447                                                   "WHERE nspname = 'pg_catalog')",
5448                                                   username_subquery);
5449                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5450                         appendPQExpBufferStr(query,
5451                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5452                                                                  "classid = 'pg_proc'::regclass AND "
5453                                                                  "objid = p.oid AND "
5454                                                                  "refclassid = 'pg_extension'::regclass AND "
5455                                                                  "deptype = 'e')");
5456                 appendPQExpBufferChar(query, ')');
5457         }
5458         else
5459         {
5460                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5461                                                   "pronamespace AS aggnamespace, "
5462                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5463                                                   "proargtypes, "
5464                                                   "(%s proowner) AS rolname, "
5465                                                   "proacl AS aggacl, "
5466                                                   "NULL AS raggacl, "
5467                                                   "NULL AS initaggacl, NULL AS initraggacl "
5468                                                   "FROM pg_proc "
5469                                                   "WHERE proisagg "
5470                                                   "AND pronamespace != "
5471                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5472                                                   username_subquery);
5473         }
5474
5475         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5476
5477         ntups = PQntuples(res);
5478         *numAggs = ntups;
5479
5480         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5481
5482         i_tableoid = PQfnumber(res, "tableoid");
5483         i_oid = PQfnumber(res, "oid");
5484         i_aggname = PQfnumber(res, "aggname");
5485         i_aggnamespace = PQfnumber(res, "aggnamespace");
5486         i_pronargs = PQfnumber(res, "pronargs");
5487         i_proargtypes = PQfnumber(res, "proargtypes");
5488         i_rolname = PQfnumber(res, "rolname");
5489         i_aggacl = PQfnumber(res, "aggacl");
5490         i_raggacl = PQfnumber(res, "raggacl");
5491         i_initaggacl = PQfnumber(res, "initaggacl");
5492         i_initraggacl = PQfnumber(res, "initraggacl");
5493
5494         for (i = 0; i < ntups; i++)
5495         {
5496                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5497                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5498                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5499                 AssignDumpId(&agginfo[i].aggfn.dobj);
5500                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5501                 agginfo[i].aggfn.dobj.namespace =
5502                         findNamespace(fout,
5503                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5504                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5505                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5506                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5507                                           agginfo[i].aggfn.dobj.name);
5508                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5509                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5510                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5511                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5512                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5513                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5514                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5515                 if (agginfo[i].aggfn.nargs == 0)
5516                         agginfo[i].aggfn.argtypes = NULL;
5517                 else
5518                 {
5519                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5520                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5521                                                   agginfo[i].aggfn.argtypes,
5522                                                   agginfo[i].aggfn.nargs);
5523                 }
5524
5525                 /* Decide whether we want to dump it */
5526                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5527
5528                 /* Do not try to dump ACL if no ACL exists. */
5529                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5530                         PQgetisnull(res, i, i_initaggacl) &&
5531                         PQgetisnull(res, i, i_initraggacl))
5532                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5533         }
5534
5535         PQclear(res);
5536
5537         destroyPQExpBuffer(query);
5538
5539         return agginfo;
5540 }
5541
5542 /*
5543  * getFuncs:
5544  *        read all the user-defined functions in the system catalogs and
5545  * return them in the FuncInfo* structure
5546  *
5547  * numFuncs is set to the number of functions read in
5548  */
5549 FuncInfo *
5550 getFuncs(Archive *fout, int *numFuncs)
5551 {
5552         DumpOptions *dopt = fout->dopt;
5553         PGresult   *res;
5554         int                     ntups;
5555         int                     i;
5556         PQExpBuffer query = createPQExpBuffer();
5557         FuncInfo   *finfo;
5558         int                     i_tableoid;
5559         int                     i_oid;
5560         int                     i_proname;
5561         int                     i_pronamespace;
5562         int                     i_rolname;
5563         int                     i_prolang;
5564         int                     i_pronargs;
5565         int                     i_proargtypes;
5566         int                     i_prorettype;
5567         int                     i_proacl;
5568         int                     i_rproacl;
5569         int                     i_initproacl;
5570         int                     i_initrproacl;
5571
5572         /*
5573          * Find all interesting functions.  This is a bit complicated:
5574          *
5575          * 1. Always exclude aggregates; those are handled elsewhere.
5576          *
5577          * 2. Always exclude functions that are internally dependent on something
5578          * else, since presumably those will be created as a result of creating
5579          * the something else.  This currently acts only to suppress constructor
5580          * functions for range types (so we only need it in 9.2 and up).  Note
5581          * this is OK only because the constructors don't have any dependencies
5582          * the range type doesn't have; otherwise we might not get creation
5583          * ordering correct.
5584          *
5585          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5586          * they're members of extensions and we are in binary-upgrade mode then
5587          * include them, since we want to dump extension members individually in
5588          * that mode.  Also, if they are used by casts or transforms then we need
5589          * to gather the information about them, though they won't be dumped if
5590          * they are built-in.  Also, in 9.6 and up, include functions in
5591          * pg_catalog if they have an ACL different from what's shown in
5592          * pg_init_privs.
5593          */
5594         if (fout->remoteVersion >= 90600)
5595         {
5596                 PQExpBuffer acl_subquery = createPQExpBuffer();
5597                 PQExpBuffer racl_subquery = createPQExpBuffer();
5598                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5599                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5600                 const char *not_agg_check;
5601
5602                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5603                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5604                                                 dopt->binary_upgrade);
5605
5606                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5607                                                  : "NOT p.proisagg");
5608
5609                 appendPQExpBuffer(query,
5610                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5611                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5612                                                   "%s AS proacl, "
5613                                                   "%s AS rproacl, "
5614                                                   "%s AS initproacl, "
5615                                                   "%s AS initrproacl, "
5616                                                   "p.pronamespace, "
5617                                                   "(%s p.proowner) AS rolname "
5618                                                   "FROM pg_proc p "
5619                                                   "LEFT JOIN pg_init_privs pip ON "
5620                                                   "(p.oid = pip.objoid "
5621                                                   "AND pip.classoid = 'pg_proc'::regclass "
5622                                                   "AND pip.objsubid = 0) "
5623                                                   "WHERE %s"
5624                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5625                                                   "WHERE classid = 'pg_proc'::regclass AND "
5626                                                   "objid = p.oid AND deptype = 'i')"
5627                                                   "\n  AND ("
5628                                                   "\n  pronamespace != "
5629                                                   "(SELECT oid FROM pg_namespace "
5630                                                   "WHERE nspname = 'pg_catalog')"
5631                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5632                                                   "\n  WHERE pg_cast.oid > %u "
5633                                                   "\n  AND p.oid = pg_cast.castfunc)"
5634                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5635                                                   "\n  WHERE pg_transform.oid > %u AND "
5636                                                   "\n  (p.oid = pg_transform.trffromsql"
5637                                                   "\n  OR p.oid = pg_transform.trftosql))",
5638                                                   acl_subquery->data,
5639                                                   racl_subquery->data,
5640                                                   initacl_subquery->data,
5641                                                   initracl_subquery->data,
5642                                                   username_subquery,
5643                                                   not_agg_check,
5644                                                   g_last_builtin_oid,
5645                                                   g_last_builtin_oid);
5646                 if (dopt->binary_upgrade)
5647                         appendPQExpBufferStr(query,
5648                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5649                                                                  "classid = 'pg_proc'::regclass AND "
5650                                                                  "objid = p.oid AND "
5651                                                                  "refclassid = 'pg_extension'::regclass AND "
5652                                                                  "deptype = 'e')");
5653                 appendPQExpBufferStr(query,
5654                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5655                 appendPQExpBufferChar(query, ')');
5656
5657                 destroyPQExpBuffer(acl_subquery);
5658                 destroyPQExpBuffer(racl_subquery);
5659                 destroyPQExpBuffer(initacl_subquery);
5660                 destroyPQExpBuffer(initracl_subquery);
5661         }
5662         else
5663         {
5664                 appendPQExpBuffer(query,
5665                                                   "SELECT tableoid, oid, proname, prolang, "
5666                                                   "pronargs, proargtypes, prorettype, proacl, "
5667                                                   "NULL as rproacl, "
5668                                                   "NULL as initproacl, NULL AS initrproacl, "
5669                                                   "pronamespace, "
5670                                                   "(%s proowner) AS rolname "
5671                                                   "FROM pg_proc p "
5672                                                   "WHERE NOT proisagg",
5673                                                   username_subquery);
5674                 if (fout->remoteVersion >= 90200)
5675                         appendPQExpBufferStr(query,
5676                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5677                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5678                                                                  "objid = p.oid AND deptype = 'i')");
5679                 appendPQExpBuffer(query,
5680                                                   "\n  AND ("
5681                                                   "\n  pronamespace != "
5682                                                   "(SELECT oid FROM pg_namespace "
5683                                                   "WHERE nspname = 'pg_catalog')"
5684                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5685                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5686                                                   "\n  AND p.oid = pg_cast.castfunc)",
5687                                                   g_last_builtin_oid);
5688
5689                 if (fout->remoteVersion >= 90500)
5690                         appendPQExpBuffer(query,
5691                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5692                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5693                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5694                                                           "\n  OR p.oid = pg_transform.trftosql))",
5695                                                           g_last_builtin_oid);
5696
5697                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5698                         appendPQExpBufferStr(query,
5699                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5700                                                                  "classid = 'pg_proc'::regclass AND "
5701                                                                  "objid = p.oid AND "
5702                                                                  "refclassid = 'pg_extension'::regclass AND "
5703                                                                  "deptype = 'e')");
5704                 appendPQExpBufferChar(query, ')');
5705         }
5706
5707         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5708
5709         ntups = PQntuples(res);
5710
5711         *numFuncs = ntups;
5712
5713         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5714
5715         i_tableoid = PQfnumber(res, "tableoid");
5716         i_oid = PQfnumber(res, "oid");
5717         i_proname = PQfnumber(res, "proname");
5718         i_pronamespace = PQfnumber(res, "pronamespace");
5719         i_rolname = PQfnumber(res, "rolname");
5720         i_prolang = PQfnumber(res, "prolang");
5721         i_pronargs = PQfnumber(res, "pronargs");
5722         i_proargtypes = PQfnumber(res, "proargtypes");
5723         i_prorettype = PQfnumber(res, "prorettype");
5724         i_proacl = PQfnumber(res, "proacl");
5725         i_rproacl = PQfnumber(res, "rproacl");
5726         i_initproacl = PQfnumber(res, "initproacl");
5727         i_initrproacl = PQfnumber(res, "initrproacl");
5728
5729         for (i = 0; i < ntups; i++)
5730         {
5731                 finfo[i].dobj.objType = DO_FUNC;
5732                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5733                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5734                 AssignDumpId(&finfo[i].dobj);
5735                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5736                 finfo[i].dobj.namespace =
5737                         findNamespace(fout,
5738                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5739                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5740                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5741                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5742                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5743                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5744                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5745                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5746                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5747                 if (finfo[i].nargs == 0)
5748                         finfo[i].argtypes = NULL;
5749                 else
5750                 {
5751                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5752                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5753                                                   finfo[i].argtypes, finfo[i].nargs);
5754                 }
5755
5756                 /* Decide whether we want to dump it */
5757                 selectDumpableObject(&(finfo[i].dobj), fout);
5758
5759                 /* Do not try to dump ACL if no ACL exists. */
5760                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5761                         PQgetisnull(res, i, i_initproacl) &&
5762                         PQgetisnull(res, i, i_initrproacl))
5763                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5764
5765                 if (strlen(finfo[i].rolname) == 0)
5766                         write_msg(NULL,
5767                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5768                                           finfo[i].dobj.name);
5769         }
5770
5771         PQclear(res);
5772
5773         destroyPQExpBuffer(query);
5774
5775         return finfo;
5776 }
5777
5778 /*
5779  * getTables
5780  *        read all the tables (no indexes)
5781  * in the system catalogs return them in the TableInfo* structure
5782  *
5783  * numTables is set to the number of tables read in
5784  */
5785 TableInfo *
5786 getTables(Archive *fout, int *numTables)
5787 {
5788         DumpOptions *dopt = fout->dopt;
5789         PGresult   *res;
5790         int                     ntups;
5791         int                     i;
5792         PQExpBuffer query = createPQExpBuffer();
5793         TableInfo  *tblinfo;
5794         int                     i_reltableoid;
5795         int                     i_reloid;
5796         int                     i_relname;
5797         int                     i_relnamespace;
5798         int                     i_relkind;
5799         int                     i_relacl;
5800         int                     i_rrelacl;
5801         int                     i_initrelacl;
5802         int                     i_initrrelacl;
5803         int                     i_rolname;
5804         int                     i_relchecks;
5805         int                     i_relhastriggers;
5806         int                     i_relhasindex;
5807         int                     i_relhasrules;
5808         int                     i_relrowsec;
5809         int                     i_relforcerowsec;
5810         int                     i_relhasoids;
5811         int                     i_relfrozenxid;
5812         int                     i_relminmxid;
5813         int                     i_toastoid;
5814         int                     i_toastfrozenxid;
5815         int                     i_toastminmxid;
5816         int                     i_relpersistence;
5817         int                     i_relispopulated;
5818         int                     i_relreplident;
5819         int                     i_owning_tab;
5820         int                     i_owning_col;
5821         int                     i_reltablespace;
5822         int                     i_reloptions;
5823         int                     i_checkoption;
5824         int                     i_toastreloptions;
5825         int                     i_reloftype;
5826         int                     i_relpages;
5827         int                     i_is_identity_sequence;
5828         int                     i_changed_acl;
5829         int                     i_partkeydef;
5830         int                     i_ispartition;
5831         int                     i_partbound;
5832
5833         /*
5834          * Find all the tables and table-like objects.
5835          *
5836          * We include system catalogs, so that we can work if a user table is
5837          * defined to inherit from a system catalog (pretty weird, but...)
5838          *
5839          * We ignore relations that are not ordinary tables, sequences, views,
5840          * materialized views, composite types, or foreign tables.
5841          *
5842          * Composite-type table entries won't be dumped as such, but we have to
5843          * make a DumpableObject for them so that we can track dependencies of the
5844          * composite type (pg_depend entries for columns of the composite type
5845          * link to the pg_class entry not the pg_type entry).
5846          *
5847          * Note: in this phase we should collect only a minimal amount of
5848          * information about each table, basically just enough to decide if it is
5849          * interesting. We must fetch all tables in this phase because otherwise
5850          * we cannot correctly identify inherited columns, owned sequences, etc.
5851          */
5852
5853         if (fout->remoteVersion >= 90600)
5854         {
5855                 char       *partkeydef = "NULL";
5856                 char       *ispartition = "false";
5857                 char       *partbound = "NULL";
5858                 char       *relhasoids = "c.relhasoids";
5859
5860                 PQExpBuffer acl_subquery = createPQExpBuffer();
5861                 PQExpBuffer racl_subquery = createPQExpBuffer();
5862                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5863                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5864
5865                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5866                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5867                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5868                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5869
5870                 /*
5871                  * Collect the information about any partitioned tables, which were
5872                  * added in PG10.
5873                  */
5874
5875                 if (fout->remoteVersion >= 100000)
5876                 {
5877                         partkeydef = "pg_get_partkeydef(c.oid)";
5878                         ispartition = "c.relispartition";
5879                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5880                 }
5881
5882                 /* In PG12 upwards WITH OIDS does not exist anymore. */
5883                 if (fout->remoteVersion >= 120000)
5884                         relhasoids = "'f'::bool";
5885
5886                 /*
5887                  * Left join to pick up dependency info linking sequences to their
5888                  * owning column, if any (note this dependency is AUTO as of 8.2)
5889                  *
5890                  * Left join to detect if any privileges are still as-set-at-init, in
5891                  * which case we won't dump out ACL commands for those.
5892                  */
5893
5894                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5895                                                 initracl_subquery, "c.relacl", "c.relowner",
5896                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5897                                                 " THEN 's' ELSE 'r' END::\"char\"",
5898                                                 dopt->binary_upgrade);
5899
5900                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5901                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5902                                                 dopt->binary_upgrade);
5903
5904                 appendPQExpBuffer(query,
5905                                                   "SELECT c.tableoid, c.oid, c.relname, "
5906                                                   "%s AS relacl, %s as rrelacl, "
5907                                                   "%s AS initrelacl, %s as initrrelacl, "
5908                                                   "c.relkind, c.relnamespace, "
5909                                                   "(%s c.relowner) AS rolname, "
5910                                                   "c.relchecks, c.relhastriggers, "
5911                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
5912                                                   "c.relrowsecurity, c.relforcerowsecurity, "
5913                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5914                                                   "tc.relfrozenxid AS tfrozenxid, "
5915                                                   "tc.relminmxid AS tminmxid, "
5916                                                   "c.relpersistence, c.relispopulated, "
5917                                                   "c.relreplident, c.relpages, "
5918                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5919                                                   "d.refobjid AS owning_tab, "
5920                                                   "d.refobjsubid AS owning_col, "
5921                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5922                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5923                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5924                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5925                                                   "tc.reloptions AS toast_reloptions, "
5926                                                   "c.relkind = '%c' AND EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_class'::regclass AND objid = c.oid AND objsubid = 0 AND refclassid = 'pg_class'::regclass AND deptype = 'i') AS is_identity_sequence, "
5927                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5928                                                   "(c.oid = pip.objoid "
5929                                                   "AND pip.classoid = 'pg_class'::regclass "
5930                                                   "AND pip.objsubid = at.attnum)"
5931                                                   "WHERE at.attrelid = c.oid AND ("
5932                                                   "%s IS NOT NULL "
5933                                                   "OR %s IS NOT NULL "
5934                                                   "OR %s IS NOT NULL "
5935                                                   "OR %s IS NOT NULL"
5936                                                   "))"
5937                                                   "AS changed_acl, "
5938                                                   "%s AS partkeydef, "
5939                                                   "%s AS ispartition, "
5940                                                   "%s AS partbound "
5941                                                   "FROM pg_class c "
5942                                                   "LEFT JOIN pg_depend d ON "
5943                                                   "(c.relkind = '%c' AND "
5944                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
5945                                                   "d.objsubid = 0 AND "
5946                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
5947                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5948                                                   "LEFT JOIN pg_init_privs pip ON "
5949                                                   "(c.oid = pip.objoid "
5950                                                   "AND pip.classoid = 'pg_class'::regclass "
5951                                                   "AND pip.objsubid = 0) "
5952                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
5953                                                   "ORDER BY c.oid",
5954                                                   acl_subquery->data,
5955                                                   racl_subquery->data,
5956                                                   initacl_subquery->data,
5957                                                   initracl_subquery->data,
5958                                                   username_subquery,
5959                                                   relhasoids,
5960                                                   RELKIND_SEQUENCE,
5961                                                   attacl_subquery->data,
5962                                                   attracl_subquery->data,
5963                                                   attinitacl_subquery->data,
5964                                                   attinitracl_subquery->data,
5965                                                   partkeydef,
5966                                                   ispartition,
5967                                                   partbound,
5968                                                   RELKIND_SEQUENCE,
5969                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
5970                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5971                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
5972                                                   RELKIND_PARTITIONED_TABLE);
5973
5974                 destroyPQExpBuffer(acl_subquery);
5975                 destroyPQExpBuffer(racl_subquery);
5976                 destroyPQExpBuffer(initacl_subquery);
5977                 destroyPQExpBuffer(initracl_subquery);
5978
5979                 destroyPQExpBuffer(attacl_subquery);
5980                 destroyPQExpBuffer(attracl_subquery);
5981                 destroyPQExpBuffer(attinitacl_subquery);
5982                 destroyPQExpBuffer(attinitracl_subquery);
5983         }
5984         else if (fout->remoteVersion >= 90500)
5985         {
5986                 /*
5987                  * Left join to pick up dependency info linking sequences to their
5988                  * owning column, if any (note this dependency is AUTO as of 8.2)
5989                  */
5990                 appendPQExpBuffer(query,
5991                                                   "SELECT c.tableoid, c.oid, c.relname, "
5992                                                   "c.relacl, NULL as rrelacl, "
5993                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
5994                                                   "c.relkind, "
5995                                                   "c.relnamespace, "
5996                                                   "(%s c.relowner) AS rolname, "
5997                                                   "c.relchecks, c.relhastriggers, "
5998                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
5999                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6000                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6001                                                   "tc.relfrozenxid AS tfrozenxid, "
6002                                                   "tc.relminmxid AS tminmxid, "
6003                                                   "c.relpersistence, c.relispopulated, "
6004                                                   "c.relreplident, c.relpages, "
6005                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6006                                                   "d.refobjid AS owning_tab, "
6007                                                   "d.refobjsubid AS owning_col, "
6008                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6009                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6010                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6011                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6012                                                   "tc.reloptions AS toast_reloptions, "
6013                                                   "NULL AS changed_acl, "
6014                                                   "NULL AS partkeydef, "
6015                                                   "false AS ispartition, "
6016                                                   "NULL AS partbound "
6017                                                   "FROM pg_class c "
6018                                                   "LEFT JOIN pg_depend d ON "
6019                                                   "(c.relkind = '%c' AND "
6020                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6021                                                   "d.objsubid = 0 AND "
6022                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6023                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6024                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6025                                                   "ORDER BY c.oid",
6026                                                   username_subquery,
6027                                                   RELKIND_SEQUENCE,
6028                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6029                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6030                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6031         }
6032         else if (fout->remoteVersion >= 90400)
6033         {
6034                 /*
6035                  * Left join to pick up dependency info linking sequences to their
6036                  * owning column, if any (note this dependency is AUTO as of 8.2)
6037                  */
6038                 appendPQExpBuffer(query,
6039                                                   "SELECT c.tableoid, c.oid, c.relname, "
6040                                                   "c.relacl, NULL as rrelacl, "
6041                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6042                                                   "c.relkind, "
6043                                                   "c.relnamespace, "
6044                                                   "(%s c.relowner) AS rolname, "
6045                                                   "c.relchecks, c.relhastriggers, "
6046                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6047                                                   "'f'::bool AS relrowsecurity, "
6048                                                   "'f'::bool AS relforcerowsecurity, "
6049                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6050                                                   "tc.relfrozenxid AS tfrozenxid, "
6051                                                   "tc.relminmxid AS tminmxid, "
6052                                                   "c.relpersistence, c.relispopulated, "
6053                                                   "c.relreplident, c.relpages, "
6054                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6055                                                   "d.refobjid AS owning_tab, "
6056                                                   "d.refobjsubid AS owning_col, "
6057                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6058                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6059                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6060                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6061                                                   "tc.reloptions AS toast_reloptions, "
6062                                                   "NULL AS changed_acl, "
6063                                                   "NULL AS partkeydef, "
6064                                                   "false AS ispartition, "
6065                                                   "NULL AS partbound "
6066                                                   "FROM pg_class c "
6067                                                   "LEFT JOIN pg_depend d ON "
6068                                                   "(c.relkind = '%c' AND "
6069                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6070                                                   "d.objsubid = 0 AND "
6071                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6072                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6073                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6074                                                   "ORDER BY c.oid",
6075                                                   username_subquery,
6076                                                   RELKIND_SEQUENCE,
6077                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6078                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6079                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6080         }
6081         else if (fout->remoteVersion >= 90300)
6082         {
6083                 /*
6084                  * Left join to pick up dependency info linking sequences to their
6085                  * owning column, if any (note this dependency is AUTO as of 8.2)
6086                  */
6087                 appendPQExpBuffer(query,
6088                                                   "SELECT c.tableoid, c.oid, c.relname, "
6089                                                   "c.relacl, NULL as rrelacl, "
6090                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6091                                                   "c.relkind, "
6092                                                   "c.relnamespace, "
6093                                                   "(%s c.relowner) AS rolname, "
6094                                                   "c.relchecks, c.relhastriggers, "
6095                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6096                                                   "'f'::bool AS relrowsecurity, "
6097                                                   "'f'::bool AS relforcerowsecurity, "
6098                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6099                                                   "tc.relfrozenxid AS tfrozenxid, "
6100                                                   "tc.relminmxid AS tminmxid, "
6101                                                   "c.relpersistence, c.relispopulated, "
6102                                                   "'d' AS relreplident, c.relpages, "
6103                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6104                                                   "d.refobjid AS owning_tab, "
6105                                                   "d.refobjsubid AS owning_col, "
6106                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6107                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6108                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6109                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6110                                                   "tc.reloptions AS toast_reloptions, "
6111                                                   "NULL AS changed_acl, "
6112                                                   "NULL AS partkeydef, "
6113                                                   "false AS ispartition, "
6114                                                   "NULL AS partbound "
6115                                                   "FROM pg_class c "
6116                                                   "LEFT JOIN pg_depend d ON "
6117                                                   "(c.relkind = '%c' AND "
6118                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6119                                                   "d.objsubid = 0 AND "
6120                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6121                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6122                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6123                                                   "ORDER BY c.oid",
6124                                                   username_subquery,
6125                                                   RELKIND_SEQUENCE,
6126                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6127                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6128                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6129         }
6130         else if (fout->remoteVersion >= 90100)
6131         {
6132                 /*
6133                  * Left join to pick up dependency info linking sequences to their
6134                  * owning column, if any (note this dependency is AUTO as of 8.2)
6135                  */
6136                 appendPQExpBuffer(query,
6137                                                   "SELECT c.tableoid, c.oid, c.relname, "
6138                                                   "c.relacl, NULL as rrelacl, "
6139                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6140                                                   "c.relkind, "
6141                                                   "c.relnamespace, "
6142                                                   "(%s c.relowner) AS rolname, "
6143                                                   "c.relchecks, c.relhastriggers, "
6144                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6145                                                   "'f'::bool AS relrowsecurity, "
6146                                                   "'f'::bool AS relforcerowsecurity, "
6147                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6148                                                   "tc.relfrozenxid AS tfrozenxid, "
6149                                                   "0 AS tminmxid, "
6150                                                   "c.relpersistence, 't' as relispopulated, "
6151                                                   "'d' AS relreplident, c.relpages, "
6152                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6153                                                   "d.refobjid AS owning_tab, "
6154                                                   "d.refobjsubid AS owning_col, "
6155                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6156                                                   "c.reloptions AS reloptions, "
6157                                                   "tc.reloptions AS toast_reloptions, "
6158                                                   "NULL AS changed_acl, "
6159                                                   "NULL AS partkeydef, "
6160                                                   "false AS ispartition, "
6161                                                   "NULL AS partbound "
6162                                                   "FROM pg_class c "
6163                                                   "LEFT JOIN pg_depend d ON "
6164                                                   "(c.relkind = '%c' AND "
6165                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6166                                                   "d.objsubid = 0 AND "
6167                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6168                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6169                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6170                                                   "ORDER BY c.oid",
6171                                                   username_subquery,
6172                                                   RELKIND_SEQUENCE,
6173                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6174                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6175                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6176         }
6177         else if (fout->remoteVersion >= 90000)
6178         {
6179                 /*
6180                  * Left join to pick up dependency info linking sequences to their
6181                  * owning column, if any (note this dependency is AUTO as of 8.2)
6182                  */
6183                 appendPQExpBuffer(query,
6184                                                   "SELECT c.tableoid, c.oid, c.relname, "
6185                                                   "c.relacl, NULL as rrelacl, "
6186                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6187                                                   "c.relkind, "
6188                                                   "c.relnamespace, "
6189                                                   "(%s c.relowner) AS rolname, "
6190                                                   "c.relchecks, c.relhastriggers, "
6191                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6192                                                   "'f'::bool AS relrowsecurity, "
6193                                                   "'f'::bool AS relforcerowsecurity, "
6194                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6195                                                   "tc.relfrozenxid AS tfrozenxid, "
6196                                                   "0 AS tminmxid, "
6197                                                   "'p' AS relpersistence, 't' as relispopulated, "
6198                                                   "'d' AS relreplident, c.relpages, "
6199                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6200                                                   "d.refobjid AS owning_tab, "
6201                                                   "d.refobjsubid AS owning_col, "
6202                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6203                                                   "c.reloptions AS reloptions, "
6204                                                   "tc.reloptions AS toast_reloptions, "
6205                                                   "NULL AS changed_acl, "
6206                                                   "NULL AS partkeydef, "
6207                                                   "false AS ispartition, "
6208                                                   "NULL AS partbound "
6209                                                   "FROM pg_class c "
6210                                                   "LEFT JOIN pg_depend d ON "
6211                                                   "(c.relkind = '%c' AND "
6212                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6213                                                   "d.objsubid = 0 AND "
6214                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6215                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6216                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6217                                                   "ORDER BY c.oid",
6218                                                   username_subquery,
6219                                                   RELKIND_SEQUENCE,
6220                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6221                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6222         }
6223         else if (fout->remoteVersion >= 80400)
6224         {
6225                 /*
6226                  * Left join to pick up dependency info linking sequences to their
6227                  * owning column, if any (note this dependency is AUTO as of 8.2)
6228                  */
6229                 appendPQExpBuffer(query,
6230                                                   "SELECT c.tableoid, c.oid, c.relname, "
6231                                                   "c.relacl, NULL as rrelacl, "
6232                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6233                                                   "c.relkind, "
6234                                                   "c.relnamespace, "
6235                                                   "(%s c.relowner) AS rolname, "
6236                                                   "c.relchecks, c.relhastriggers, "
6237                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6238                                                   "'f'::bool AS relrowsecurity, "
6239                                                   "'f'::bool AS relforcerowsecurity, "
6240                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6241                                                   "tc.relfrozenxid AS tfrozenxid, "
6242                                                   "0 AS tminmxid, "
6243                                                   "'p' AS relpersistence, 't' as relispopulated, "
6244                                                   "'d' AS relreplident, c.relpages, "
6245                                                   "NULL AS reloftype, "
6246                                                   "d.refobjid AS owning_tab, "
6247                                                   "d.refobjsubid AS owning_col, "
6248                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6249                                                   "c.reloptions AS reloptions, "
6250                                                   "tc.reloptions AS toast_reloptions, "
6251                                                   "NULL AS changed_acl, "
6252                                                   "NULL AS partkeydef, "
6253                                                   "false AS ispartition, "
6254                                                   "NULL AS partbound "
6255                                                   "FROM pg_class c "
6256                                                   "LEFT JOIN pg_depend d ON "
6257                                                   "(c.relkind = '%c' AND "
6258                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6259                                                   "d.objsubid = 0 AND "
6260                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6261                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6262                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6263                                                   "ORDER BY c.oid",
6264                                                   username_subquery,
6265                                                   RELKIND_SEQUENCE,
6266                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6267                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6268         }
6269         else if (fout->remoteVersion >= 80200)
6270         {
6271                 /*
6272                  * Left join to pick up dependency info linking sequences to their
6273                  * owning column, if any (note this dependency is AUTO as of 8.2)
6274                  */
6275                 appendPQExpBuffer(query,
6276                                                   "SELECT c.tableoid, c.oid, c.relname, "
6277                                                   "c.relacl, NULL as rrelacl, "
6278                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6279                                                   "c.relkind, "
6280                                                   "c.relnamespace, "
6281                                                   "(%s c.relowner) AS rolname, "
6282                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6283                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6284                                                   "'f'::bool AS relrowsecurity, "
6285                                                   "'f'::bool AS relforcerowsecurity, "
6286                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6287                                                   "tc.relfrozenxid AS tfrozenxid, "
6288                                                   "0 AS tminmxid, "
6289                                                   "'p' AS relpersistence, 't' as relispopulated, "
6290                                                   "'d' AS relreplident, c.relpages, "
6291                                                   "NULL AS reloftype, "
6292                                                   "d.refobjid AS owning_tab, "
6293                                                   "d.refobjsubid AS owning_col, "
6294                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6295                                                   "c.reloptions AS reloptions, "
6296                                                   "NULL AS toast_reloptions, "
6297                                                   "NULL AS changed_acl, "
6298                                                   "NULL AS partkeydef, "
6299                                                   "false AS ispartition, "
6300                                                   "NULL AS partbound "
6301                                                   "FROM pg_class c "
6302                                                   "LEFT JOIN pg_depend d ON "
6303                                                   "(c.relkind = '%c' AND "
6304                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6305                                                   "d.objsubid = 0 AND "
6306                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6307                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6308                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6309                                                   "ORDER BY c.oid",
6310                                                   username_subquery,
6311                                                   RELKIND_SEQUENCE,
6312                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6313                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6314         }
6315         else
6316         {
6317                 /*
6318                  * Left join to pick up dependency info linking sequences to their
6319                  * owning column, if any
6320                  */
6321                 appendPQExpBuffer(query,
6322                                                   "SELECT c.tableoid, c.oid, relname, "
6323                                                   "relacl, NULL as rrelacl, "
6324                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6325                                                   "relkind, relnamespace, "
6326                                                   "(%s relowner) AS rolname, "
6327                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6328                                                   "relhasindex, relhasrules, relhasoids, "
6329                                                   "'f'::bool AS relrowsecurity, "
6330                                                   "'f'::bool AS relforcerowsecurity, "
6331                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6332                                                   "0 AS toid, "
6333                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6334                                                   "'p' AS relpersistence, 't' as relispopulated, "
6335                                                   "'d' AS relreplident, relpages, "
6336                                                   "NULL AS reloftype, "
6337                                                   "d.refobjid AS owning_tab, "
6338                                                   "d.refobjsubid AS owning_col, "
6339                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6340                                                   "NULL AS reloptions, "
6341                                                   "NULL AS toast_reloptions, "
6342                                                   "NULL AS changed_acl, "
6343                                                   "NULL AS partkeydef, "
6344                                                   "false AS ispartition, "
6345                                                   "NULL AS partbound "
6346                                                   "FROM pg_class c "
6347                                                   "LEFT JOIN pg_depend d ON "
6348                                                   "(c.relkind = '%c' AND "
6349                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6350                                                   "d.objsubid = 0 AND "
6351                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6352                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6353                                                   "ORDER BY c.oid",
6354                                                   username_subquery,
6355                                                   RELKIND_SEQUENCE,
6356                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6357                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6358         }
6359
6360         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6361
6362         ntups = PQntuples(res);
6363
6364         *numTables = ntups;
6365
6366         /*
6367          * Extract data from result and lock dumpable tables.  We do the locking
6368          * before anything else, to minimize the window wherein a table could
6369          * disappear under us.
6370          *
6371          * Note that we have to save info about all tables here, even when dumping
6372          * only one, because we don't yet know which tables might be inheritance
6373          * ancestors of the target table.
6374          */
6375         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6376
6377         i_reltableoid = PQfnumber(res, "tableoid");
6378         i_reloid = PQfnumber(res, "oid");
6379         i_relname = PQfnumber(res, "relname");
6380         i_relnamespace = PQfnumber(res, "relnamespace");
6381         i_relacl = PQfnumber(res, "relacl");
6382         i_rrelacl = PQfnumber(res, "rrelacl");
6383         i_initrelacl = PQfnumber(res, "initrelacl");
6384         i_initrrelacl = PQfnumber(res, "initrrelacl");
6385         i_relkind = PQfnumber(res, "relkind");
6386         i_rolname = PQfnumber(res, "rolname");
6387         i_relchecks = PQfnumber(res, "relchecks");
6388         i_relhastriggers = PQfnumber(res, "relhastriggers");
6389         i_relhasindex = PQfnumber(res, "relhasindex");
6390         i_relhasrules = PQfnumber(res, "relhasrules");
6391         i_relrowsec = PQfnumber(res, "relrowsecurity");
6392         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6393         i_relhasoids = PQfnumber(res, "relhasoids");
6394         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6395         i_relminmxid = PQfnumber(res, "relminmxid");
6396         i_toastoid = PQfnumber(res, "toid");
6397         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6398         i_toastminmxid = PQfnumber(res, "tminmxid");
6399         i_relpersistence = PQfnumber(res, "relpersistence");
6400         i_relispopulated = PQfnumber(res, "relispopulated");
6401         i_relreplident = PQfnumber(res, "relreplident");
6402         i_relpages = PQfnumber(res, "relpages");
6403         i_owning_tab = PQfnumber(res, "owning_tab");
6404         i_owning_col = PQfnumber(res, "owning_col");
6405         i_reltablespace = PQfnumber(res, "reltablespace");
6406         i_reloptions = PQfnumber(res, "reloptions");
6407         i_checkoption = PQfnumber(res, "checkoption");
6408         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6409         i_reloftype = PQfnumber(res, "reloftype");
6410         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6411         i_changed_acl = PQfnumber(res, "changed_acl");
6412         i_partkeydef = PQfnumber(res, "partkeydef");
6413         i_ispartition = PQfnumber(res, "ispartition");
6414         i_partbound = PQfnumber(res, "partbound");
6415
6416         if (dopt->lockWaitTimeout)
6417         {
6418                 /*
6419                  * Arrange to fail instead of waiting forever for a table lock.
6420                  *
6421                  * NB: this coding assumes that the only queries issued within the
6422                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6423                  * applied to other things too.
6424                  */
6425                 resetPQExpBuffer(query);
6426                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6427                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6428                 ExecuteSqlStatement(fout, query->data);
6429         }
6430
6431         for (i = 0; i < ntups; i++)
6432         {
6433                 tblinfo[i].dobj.objType = DO_TABLE;
6434                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6435                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6436                 AssignDumpId(&tblinfo[i].dobj);
6437                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6438                 tblinfo[i].dobj.namespace =
6439                         findNamespace(fout,
6440                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6441                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6442                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6443                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6444                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6445                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6446                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6447                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6448                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6449                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6450                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6451                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6452                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6453                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6454                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6455                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6456                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6457                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6458                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6459                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6460                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6461                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6462                 if (PQgetisnull(res, i, i_reloftype))
6463                         tblinfo[i].reloftype = NULL;
6464                 else
6465                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6466                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6467                 if (PQgetisnull(res, i, i_owning_tab))
6468                 {
6469                         tblinfo[i].owning_tab = InvalidOid;
6470                         tblinfo[i].owning_col = 0;
6471                 }
6472                 else
6473                 {
6474                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6475                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6476                 }
6477                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6478                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6479                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6480                         tblinfo[i].checkoption = NULL;
6481                 else
6482                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6483                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6484
6485                 /* other fields were zeroed above */
6486
6487                 /*
6488                  * Decide whether we want to dump this table.
6489                  */
6490                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6491                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6492                 else
6493                         selectDumpableTable(&tblinfo[i], fout);
6494
6495                 /*
6496                  * If the table-level and all column-level ACLs for this table are
6497                  * unchanged, then we don't need to worry about including the ACLs for
6498                  * this table.  If any column-level ACLs have been changed, the
6499                  * 'changed_acl' column from the query will indicate that.
6500                  *
6501                  * This can result in a significant performance improvement in cases
6502                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6503                  */
6504                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6505                         PQgetisnull(res, i, i_initrelacl) &&
6506                         PQgetisnull(res, i, i_initrrelacl) &&
6507                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6508                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6509
6510                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6511                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6512                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6513
6514                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6515                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6516
6517                 /* Partition key string or NULL */
6518                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6519                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6520                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6521
6522                 /*
6523                  * Read-lock target tables to make sure they aren't DROPPED or altered
6524                  * in schema before we get around to dumping them.
6525                  *
6526                  * Note that we don't explicitly lock parents of the target tables; we
6527                  * assume our lock on the child is enough to prevent schema
6528                  * alterations to parent tables.
6529                  *
6530                  * NOTE: it'd be kinda nice to lock other relations too, not only
6531                  * plain or partitioned tables, but the backend doesn't presently
6532                  * allow that.
6533                  *
6534                  * We only need to lock the table for certain components; see
6535                  * pg_dump.h
6536                  */
6537                 if (tblinfo[i].dobj.dump &&
6538                         (tblinfo[i].relkind == RELKIND_RELATION ||
6539                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6540                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6541                 {
6542                         resetPQExpBuffer(query);
6543                         appendPQExpBuffer(query,
6544                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6545                                                           fmtQualifiedDumpable(&tblinfo[i]));
6546                         ExecuteSqlStatement(fout, query->data);
6547                 }
6548
6549                 /* Emit notice if join for owner failed */
6550                 if (strlen(tblinfo[i].rolname) == 0)
6551                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6552                                           tblinfo[i].dobj.name);
6553         }
6554
6555         if (dopt->lockWaitTimeout)
6556         {
6557                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6558         }
6559
6560         PQclear(res);
6561
6562         destroyPQExpBuffer(query);
6563
6564         return tblinfo;
6565 }
6566
6567 /*
6568  * getOwnedSeqs
6569  *        identify owned sequences and mark them as dumpable if owning table is
6570  *
6571  * We used to do this in getTables(), but it's better to do it after the
6572  * index used by findTableByOid() has been set up.
6573  */
6574 void
6575 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6576 {
6577         int                     i;
6578
6579         /*
6580          * Force sequences that are "owned" by table columns to be dumped whenever
6581          * their owning table is being dumped.
6582          */
6583         for (i = 0; i < numTables; i++)
6584         {
6585                 TableInfo  *seqinfo = &tblinfo[i];
6586                 TableInfo  *owning_tab;
6587
6588                 if (!OidIsValid(seqinfo->owning_tab))
6589                         continue;                       /* not an owned sequence */
6590
6591                 owning_tab = findTableByOid(seqinfo->owning_tab);
6592                 if (owning_tab == NULL)
6593                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6594                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6595
6596                 /*
6597                  * Only dump identity sequences if we're going to dump the table that
6598                  * it belongs to.
6599                  */
6600                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6601                         seqinfo->is_identity_sequence)
6602                 {
6603                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6604                         continue;
6605                 }
6606
6607                 /*
6608                  * Otherwise we need to dump the components that are being dumped for
6609                  * the table and any components which the sequence is explicitly
6610                  * marked with.
6611                  *
6612                  * We can't simply use the set of components which are being dumped
6613                  * for the table as the table might be in an extension (and only the
6614                  * non-extension components, eg: ACLs if changed, security labels, and
6615                  * policies, are being dumped) while the sequence is not (and
6616                  * therefore the definition and other components should also be
6617                  * dumped).
6618                  *
6619                  * If the sequence is part of the extension then it should be properly
6620                  * marked by checkExtensionMembership() and this will be a no-op as
6621                  * the table will be equivalently marked.
6622                  */
6623                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6624
6625                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6626                         seqinfo->interesting = true;
6627         }
6628 }
6629
6630 /*
6631  * getInherits
6632  *        read all the inheritance information
6633  * from the system catalogs return them in the InhInfo* structure
6634  *
6635  * numInherits is set to the number of pairs read in
6636  */
6637 InhInfo *
6638 getInherits(Archive *fout, int *numInherits)
6639 {
6640         PGresult   *res;
6641         int                     ntups;
6642         int                     i;
6643         PQExpBuffer query = createPQExpBuffer();
6644         InhInfo    *inhinfo;
6645
6646         int                     i_inhrelid;
6647         int                     i_inhparent;
6648
6649         /*
6650          * Find all the inheritance information, excluding implicit inheritance
6651          * via partitioning.  We handle that case using getPartitions(), because
6652          * we want more information about partitions than just the parent-child
6653          * relationship.
6654          */
6655         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6656
6657         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6658
6659         ntups = PQntuples(res);
6660
6661         *numInherits = ntups;
6662
6663         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6664
6665         i_inhrelid = PQfnumber(res, "inhrelid");
6666         i_inhparent = PQfnumber(res, "inhparent");
6667
6668         for (i = 0; i < ntups; i++)
6669         {
6670                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6671                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6672         }
6673
6674         PQclear(res);
6675
6676         destroyPQExpBuffer(query);
6677
6678         return inhinfo;
6679 }
6680
6681 /*
6682  * getIndexes
6683  *        get information about every index on a dumpable table
6684  *
6685  * Note: index data is not returned directly to the caller, but it
6686  * does get entered into the DumpableObject tables.
6687  */
6688 void
6689 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6690 {
6691         int                     i,
6692                                 j;
6693         PQExpBuffer query = createPQExpBuffer();
6694         PGresult   *res;
6695         IndxInfo   *indxinfo;
6696         ConstraintInfo *constrinfo;
6697         int                     i_tableoid,
6698                                 i_oid,
6699                                 i_indexname,
6700                                 i_parentidx,
6701                                 i_indexdef,
6702                                 i_indnkeyatts,
6703                                 i_indnatts,
6704                                 i_indkey,
6705                                 i_indisclustered,
6706                                 i_indisreplident,
6707                                 i_contype,
6708                                 i_conname,
6709                                 i_condeferrable,
6710                                 i_condeferred,
6711                                 i_contableoid,
6712                                 i_conoid,
6713                                 i_condef,
6714                                 i_tablespace,
6715                                 i_indreloptions,
6716                                 i_indstatcols,
6717                                 i_indstatvals;
6718         int                     ntups;
6719
6720         for (i = 0; i < numTables; i++)
6721         {
6722                 TableInfo  *tbinfo = &tblinfo[i];
6723
6724                 if (!tbinfo->hasindex)
6725                         continue;
6726
6727                 /*
6728                  * Ignore indexes of tables whose definitions are not to be dumped.
6729                  *
6730                  * We also need indexes on partitioned tables which have partitions to
6731                  * be dumped, in order to dump the indexes on the partitions.
6732                  */
6733                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6734                         !tbinfo->interesting)
6735                         continue;
6736
6737                 if (g_verbose)
6738                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6739                                           tbinfo->dobj.namespace->dobj.name,
6740                                           tbinfo->dobj.name);
6741
6742                 /*
6743                  * The point of the messy-looking outer join is to find a constraint
6744                  * that is related by an internal dependency link to the index. If we
6745                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6746                  * assume an index won't have more than one internal dependency.
6747                  *
6748                  * As of 9.0 we don't need to look at pg_depend but can check for a
6749                  * match to pg_constraint.conindid.  The check on conrelid is
6750                  * redundant but useful because that column is indexed while conindid
6751                  * is not.
6752                  */
6753                 resetPQExpBuffer(query);
6754                 if (fout->remoteVersion >= 110000)
6755                 {
6756                         appendPQExpBuffer(query,
6757                                                           "SELECT t.tableoid, t.oid, "
6758                                                           "t.relname AS indexname, "
6759                                                           "inh.inhparent AS parentidx, "
6760                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6761                                                           "i.indnkeyatts AS indnkeyatts, "
6762                                                           "i.indnatts AS indnatts, "
6763                                                           "i.indkey, i.indisclustered, "
6764                                                           "i.indisreplident, "
6765                                                           "c.contype, c.conname, "
6766                                                           "c.condeferrable, c.condeferred, "
6767                                                           "c.tableoid AS contableoid, "
6768                                                           "c.oid AS conoid, "
6769                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6770                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6771                                                           "t.reloptions AS indreloptions, "
6772                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6773                                                           "  FROM pg_catalog.pg_attribute "
6774                                                           "  WHERE attrelid = i.indexrelid AND "
6775                                                           "    attstattarget >= 0) AS indstatcols,"
6776                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6777                                                           "  FROM pg_catalog.pg_attribute "
6778                                                           "  WHERE attrelid = i.indexrelid AND "
6779                                                           "    attstattarget >= 0) AS indstatvals "
6780                                                           "FROM pg_catalog.pg_index i "
6781                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6782                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6783                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6784                                                           "ON (i.indrelid = c.conrelid AND "
6785                                                           "i.indexrelid = c.conindid AND "
6786                                                           "c.contype IN ('p','u','x')) "
6787                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6788                                                           "ON (inh.inhrelid = indexrelid) "
6789                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6790                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6791                                                           "AND i.indisready "
6792                                                           "ORDER BY indexname",
6793                                                           tbinfo->dobj.catId.oid);
6794                 }
6795                 else if (fout->remoteVersion >= 90400)
6796                 {
6797                         /*
6798                          * the test on indisready is necessary in 9.2, and harmless in
6799                          * earlier/later versions
6800                          */
6801                         appendPQExpBuffer(query,
6802                                                           "SELECT t.tableoid, t.oid, "
6803                                                           "t.relname AS indexname, "
6804                                                           "0 AS parentidx, "
6805                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6806                                                           "i.indnatts AS indnkeyatts, "
6807                                                           "i.indnatts AS indnatts, "
6808                                                           "i.indkey, i.indisclustered, "
6809                                                           "i.indisreplident, "
6810                                                           "c.contype, c.conname, "
6811                                                           "c.condeferrable, c.condeferred, "
6812                                                           "c.tableoid AS contableoid, "
6813                                                           "c.oid AS conoid, "
6814                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6815                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6816                                                           "t.reloptions AS indreloptions, "
6817                                                           "'' AS indstatcols, "
6818                                                           "'' AS indstatvals "
6819                                                           "FROM pg_catalog.pg_index i "
6820                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6821                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6822                                                           "ON (i.indrelid = c.conrelid AND "
6823                                                           "i.indexrelid = c.conindid AND "
6824                                                           "c.contype IN ('p','u','x')) "
6825                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6826                                                           "AND i.indisvalid AND i.indisready "
6827                                                           "ORDER BY indexname",
6828                                                           tbinfo->dobj.catId.oid);
6829                 }
6830                 else if (fout->remoteVersion >= 90000)
6831                 {
6832                         /*
6833                          * the test on indisready is necessary in 9.2, and harmless in
6834                          * earlier/later versions
6835                          */
6836                         appendPQExpBuffer(query,
6837                                                           "SELECT t.tableoid, t.oid, "
6838                                                           "t.relname AS indexname, "
6839                                                           "0 AS parentidx, "
6840                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6841                                                           "i.indnatts AS indnkeyatts, "
6842                                                           "i.indnatts AS indnatts, "
6843                                                           "i.indkey, i.indisclustered, "
6844                                                           "false AS indisreplident, "
6845                                                           "c.contype, c.conname, "
6846                                                           "c.condeferrable, c.condeferred, "
6847                                                           "c.tableoid AS contableoid, "
6848                                                           "c.oid AS conoid, "
6849                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6850                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6851                                                           "t.reloptions AS indreloptions, "
6852                                                           "'' AS indstatcols, "
6853                                                           "'' AS indstatvals "
6854                                                           "FROM pg_catalog.pg_index i "
6855                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6856                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6857                                                           "ON (i.indrelid = c.conrelid AND "
6858                                                           "i.indexrelid = c.conindid AND "
6859                                                           "c.contype IN ('p','u','x')) "
6860                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6861                                                           "AND i.indisvalid AND i.indisready "
6862                                                           "ORDER BY indexname",
6863                                                           tbinfo->dobj.catId.oid);
6864                 }
6865                 else if (fout->remoteVersion >= 80200)
6866                 {
6867                         appendPQExpBuffer(query,
6868                                                           "SELECT t.tableoid, t.oid, "
6869                                                           "t.relname AS indexname, "
6870                                                           "0 AS parentidx, "
6871                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6872                                                           "i.indnatts AS indnkeyatts, "
6873                                                           "i.indnatts AS indnatts, "
6874                                                           "i.indkey, i.indisclustered, "
6875                                                           "false AS indisreplident, "
6876                                                           "c.contype, c.conname, "
6877                                                           "c.condeferrable, c.condeferred, "
6878                                                           "c.tableoid AS contableoid, "
6879                                                           "c.oid AS conoid, "
6880                                                           "null AS condef, "
6881                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6882                                                           "t.reloptions AS indreloptions, "
6883                                                           "'' AS indstatcols, "
6884                                                           "'' AS indstatvals "
6885                                                           "FROM pg_catalog.pg_index i "
6886                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6887                                                           "LEFT JOIN pg_catalog.pg_depend d "
6888                                                           "ON (d.classid = t.tableoid "
6889                                                           "AND d.objid = t.oid "
6890                                                           "AND d.deptype = 'i') "
6891                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6892                                                           "ON (d.refclassid = c.tableoid "
6893                                                           "AND d.refobjid = c.oid) "
6894                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6895                                                           "AND i.indisvalid "
6896                                                           "ORDER BY indexname",
6897                                                           tbinfo->dobj.catId.oid);
6898                 }
6899                 else
6900                 {
6901                         appendPQExpBuffer(query,
6902                                                           "SELECT t.tableoid, t.oid, "
6903                                                           "t.relname AS indexname, "
6904                                                           "0 AS parentidx, "
6905                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6906                                                           "t.relnatts AS indnkeyatts, "
6907                                                           "t.relnatts AS indnatts, "
6908                                                           "i.indkey, i.indisclustered, "
6909                                                           "false AS indisreplident, "
6910                                                           "c.contype, c.conname, "
6911                                                           "c.condeferrable, c.condeferred, "
6912                                                           "c.tableoid AS contableoid, "
6913                                                           "c.oid AS conoid, "
6914                                                           "null AS condef, "
6915                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6916                                                           "null AS indreloptions, "
6917                                                           "'' AS indstatcols, "
6918                                                           "'' AS indstatvals "
6919                                                           "FROM pg_catalog.pg_index i "
6920                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6921                                                           "LEFT JOIN pg_catalog.pg_depend d "
6922                                                           "ON (d.classid = t.tableoid "
6923                                                           "AND d.objid = t.oid "
6924                                                           "AND d.deptype = 'i') "
6925                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6926                                                           "ON (d.refclassid = c.tableoid "
6927                                                           "AND d.refobjid = c.oid) "
6928                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6929                                                           "ORDER BY indexname",
6930                                                           tbinfo->dobj.catId.oid);
6931                 }
6932
6933                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6934
6935                 ntups = PQntuples(res);
6936
6937                 i_tableoid = PQfnumber(res, "tableoid");
6938                 i_oid = PQfnumber(res, "oid");
6939                 i_indexname = PQfnumber(res, "indexname");
6940                 i_parentidx = PQfnumber(res, "parentidx");
6941                 i_indexdef = PQfnumber(res, "indexdef");
6942                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
6943                 i_indnatts = PQfnumber(res, "indnatts");
6944                 i_indkey = PQfnumber(res, "indkey");
6945                 i_indisclustered = PQfnumber(res, "indisclustered");
6946                 i_indisreplident = PQfnumber(res, "indisreplident");
6947                 i_contype = PQfnumber(res, "contype");
6948                 i_conname = PQfnumber(res, "conname");
6949                 i_condeferrable = PQfnumber(res, "condeferrable");
6950                 i_condeferred = PQfnumber(res, "condeferred");
6951                 i_contableoid = PQfnumber(res, "contableoid");
6952                 i_conoid = PQfnumber(res, "conoid");
6953                 i_condef = PQfnumber(res, "condef");
6954                 i_tablespace = PQfnumber(res, "tablespace");
6955                 i_indreloptions = PQfnumber(res, "indreloptions");
6956                 i_indstatcols = PQfnumber(res, "indstatcols");
6957                 i_indstatvals = PQfnumber(res, "indstatvals");
6958
6959                 tbinfo->indexes = indxinfo =
6960                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
6961                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6962                 tbinfo->numIndexes = ntups;
6963
6964                 for (j = 0; j < ntups; j++)
6965                 {
6966                         char            contype;
6967
6968                         indxinfo[j].dobj.objType = DO_INDEX;
6969                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6970                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6971                         AssignDumpId(&indxinfo[j].dobj);
6972                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
6973                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6974                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6975                         indxinfo[j].indextable = tbinfo;
6976                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
6977                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
6978                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
6979                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
6980                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
6981                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
6982                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
6983                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
6984                         parseOidArray(PQgetvalue(res, j, i_indkey),
6985                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
6986                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
6987                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
6988                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
6989                         contype = *(PQgetvalue(res, j, i_contype));
6990
6991                         if (contype == 'p' || contype == 'u' || contype == 'x')
6992                         {
6993                                 /*
6994                                  * If we found a constraint matching the index, create an
6995                                  * entry for it.
6996                                  */
6997                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
6998                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6999                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7000                                 AssignDumpId(&constrinfo[j].dobj);
7001                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7002                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7003                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7004                                 constrinfo[j].contable = tbinfo;
7005                                 constrinfo[j].condomain = NULL;
7006                                 constrinfo[j].contype = contype;
7007                                 if (contype == 'x')
7008                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7009                                 else
7010                                         constrinfo[j].condef = NULL;
7011                                 constrinfo[j].confrelid = InvalidOid;
7012                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7013                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7014                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7015                                 constrinfo[j].conislocal = true;
7016                                 constrinfo[j].separate = true;
7017
7018                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7019                         }
7020                         else
7021                         {
7022                                 /* Plain secondary index */
7023                                 indxinfo[j].indexconstraint = 0;
7024                         }
7025                 }
7026
7027                 PQclear(res);
7028         }
7029
7030         destroyPQExpBuffer(query);
7031 }
7032
7033 /*
7034  * getExtendedStatistics
7035  *        get information about extended-statistics objects.
7036  *
7037  * Note: extended statistics data is not returned directly to the caller, but
7038  * it does get entered into the DumpableObject tables.
7039  */
7040 void
7041 getExtendedStatistics(Archive *fout)
7042 {
7043         PQExpBuffer query;
7044         PGresult   *res;
7045         StatsExtInfo *statsextinfo;
7046         int                     ntups;
7047         int                     i_tableoid;
7048         int                     i_oid;
7049         int                     i_stxname;
7050         int                     i_stxnamespace;
7051         int                     i_rolname;
7052         int                     i;
7053
7054         /* Extended statistics were new in v10 */
7055         if (fout->remoteVersion < 100000)
7056                 return;
7057
7058         query = createPQExpBuffer();
7059
7060         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7061                                           "stxnamespace, (%s stxowner) AS rolname "
7062                                           "FROM pg_catalog.pg_statistic_ext",
7063                                           username_subquery);
7064
7065         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7066
7067         ntups = PQntuples(res);
7068
7069         i_tableoid = PQfnumber(res, "tableoid");
7070         i_oid = PQfnumber(res, "oid");
7071         i_stxname = PQfnumber(res, "stxname");
7072         i_stxnamespace = PQfnumber(res, "stxnamespace");
7073         i_rolname = PQfnumber(res, "rolname");
7074
7075         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7076
7077         for (i = 0; i < ntups; i++)
7078         {
7079                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7080                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7081                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7082                 AssignDumpId(&statsextinfo[i].dobj);
7083                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7084                 statsextinfo[i].dobj.namespace =
7085                         findNamespace(fout,
7086                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7087                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7088
7089                 /* Decide whether we want to dump it */
7090                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7091
7092                 /* Stats objects do not currently have ACLs. */
7093                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7094         }
7095
7096         PQclear(res);
7097         destroyPQExpBuffer(query);
7098 }
7099
7100 /*
7101  * getConstraints
7102  *
7103  * Get info about constraints on dumpable tables.
7104  *
7105  * Currently handles foreign keys only.
7106  * Unique and primary key constraints are handled with indexes,
7107  * while check constraints are processed in getTableAttrs().
7108  */
7109 void
7110 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7111 {
7112         int                     i,
7113                                 j;
7114         ConstraintInfo *constrinfo;
7115         PQExpBuffer query;
7116         PGresult   *res;
7117         int                     i_contableoid,
7118                                 i_conoid,
7119                                 i_conname,
7120                                 i_confrelid,
7121                                 i_condef;
7122         int                     ntups;
7123
7124         query = createPQExpBuffer();
7125
7126         for (i = 0; i < numTables; i++)
7127         {
7128                 TableInfo  *tbinfo = &tblinfo[i];
7129
7130                 /*
7131                  * For partitioned tables, foreign keys have no triggers so they must
7132                  * be included anyway in case some foreign keys are defined.
7133                  */
7134                 if ((!tbinfo->hastriggers &&
7135                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7136                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7137                         continue;
7138
7139                 if (g_verbose)
7140                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7141                                           tbinfo->dobj.namespace->dobj.name,
7142                                           tbinfo->dobj.name);
7143
7144                 resetPQExpBuffer(query);
7145                 if (fout->remoteVersion >= 110000)
7146                         appendPQExpBuffer(query,
7147                                                           "SELECT tableoid, oid, conname, confrelid, "
7148                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7149                                                           "FROM pg_catalog.pg_constraint "
7150                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7151                                                           "AND conparentid = 0 "
7152                                                           "AND contype = 'f'",
7153                                                           tbinfo->dobj.catId.oid);
7154                 else
7155                         appendPQExpBuffer(query,
7156                                                           "SELECT tableoid, oid, conname, confrelid, "
7157                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7158                                                           "FROM pg_catalog.pg_constraint "
7159                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7160                                                           "AND contype = 'f'",
7161                                                           tbinfo->dobj.catId.oid);
7162                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7163
7164                 ntups = PQntuples(res);
7165
7166                 i_contableoid = PQfnumber(res, "tableoid");
7167                 i_conoid = PQfnumber(res, "oid");
7168                 i_conname = PQfnumber(res, "conname");
7169                 i_confrelid = PQfnumber(res, "confrelid");
7170                 i_condef = PQfnumber(res, "condef");
7171
7172                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7173
7174                 for (j = 0; j < ntups; j++)
7175                 {
7176                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7177                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7178                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7179                         AssignDumpId(&constrinfo[j].dobj);
7180                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7181                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7182                         constrinfo[j].contable = tbinfo;
7183                         constrinfo[j].condomain = NULL;
7184                         constrinfo[j].contype = 'f';
7185                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7186                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7187                         constrinfo[j].conindex = 0;
7188                         constrinfo[j].condeferrable = false;
7189                         constrinfo[j].condeferred = false;
7190                         constrinfo[j].conislocal = true;
7191                         constrinfo[j].separate = true;
7192                 }
7193
7194                 PQclear(res);
7195         }
7196
7197         destroyPQExpBuffer(query);
7198 }
7199
7200 /*
7201  * getDomainConstraints
7202  *
7203  * Get info about constraints on a domain.
7204  */
7205 static void
7206 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7207 {
7208         int                     i;
7209         ConstraintInfo *constrinfo;
7210         PQExpBuffer query;
7211         PGresult   *res;
7212         int                     i_tableoid,
7213                                 i_oid,
7214                                 i_conname,
7215                                 i_consrc;
7216         int                     ntups;
7217
7218         query = createPQExpBuffer();
7219
7220         if (fout->remoteVersion >= 90100)
7221                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7222                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7223                                                   "convalidated "
7224                                                   "FROM pg_catalog.pg_constraint "
7225                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7226                                                   "ORDER BY conname",
7227                                                   tyinfo->dobj.catId.oid);
7228
7229         else
7230                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7231                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7232                                                   "true as convalidated "
7233                                                   "FROM pg_catalog.pg_constraint "
7234                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7235                                                   "ORDER BY conname",
7236                                                   tyinfo->dobj.catId.oid);
7237
7238         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7239
7240         ntups = PQntuples(res);
7241
7242         i_tableoid = PQfnumber(res, "tableoid");
7243         i_oid = PQfnumber(res, "oid");
7244         i_conname = PQfnumber(res, "conname");
7245         i_consrc = PQfnumber(res, "consrc");
7246
7247         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7248
7249         tyinfo->nDomChecks = ntups;
7250         tyinfo->domChecks = constrinfo;
7251
7252         for (i = 0; i < ntups; i++)
7253         {
7254                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7255
7256                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7257                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7258                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7259                 AssignDumpId(&constrinfo[i].dobj);
7260                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7261                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7262                 constrinfo[i].contable = NULL;
7263                 constrinfo[i].condomain = tyinfo;
7264                 constrinfo[i].contype = 'c';
7265                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7266                 constrinfo[i].confrelid = InvalidOid;
7267                 constrinfo[i].conindex = 0;
7268                 constrinfo[i].condeferrable = false;
7269                 constrinfo[i].condeferred = false;
7270                 constrinfo[i].conislocal = true;
7271
7272                 constrinfo[i].separate = !validated;
7273
7274                 /*
7275                  * Make the domain depend on the constraint, ensuring it won't be
7276                  * output till any constraint dependencies are OK.  If the constraint
7277                  * has not been validated, it's going to be dumped after the domain
7278                  * anyway, so this doesn't matter.
7279                  */
7280                 if (validated)
7281                         addObjectDependency(&tyinfo->dobj,
7282                                                                 constrinfo[i].dobj.dumpId);
7283         }
7284
7285         PQclear(res);
7286
7287         destroyPQExpBuffer(query);
7288 }
7289
7290 /*
7291  * getRules
7292  *        get basic information about every rule in the system
7293  *
7294  * numRules is set to the number of rules read in
7295  */
7296 RuleInfo *
7297 getRules(Archive *fout, int *numRules)
7298 {
7299         PGresult   *res;
7300         int                     ntups;
7301         int                     i;
7302         PQExpBuffer query = createPQExpBuffer();
7303         RuleInfo   *ruleinfo;
7304         int                     i_tableoid;
7305         int                     i_oid;
7306         int                     i_rulename;
7307         int                     i_ruletable;
7308         int                     i_ev_type;
7309         int                     i_is_instead;
7310         int                     i_ev_enabled;
7311
7312         if (fout->remoteVersion >= 80300)
7313         {
7314                 appendPQExpBufferStr(query, "SELECT "
7315                                                          "tableoid, oid, rulename, "
7316                                                          "ev_class AS ruletable, ev_type, is_instead, "
7317                                                          "ev_enabled "
7318                                                          "FROM pg_rewrite "
7319                                                          "ORDER BY oid");
7320         }
7321         else
7322         {
7323                 appendPQExpBufferStr(query, "SELECT "
7324                                                          "tableoid, oid, rulename, "
7325                                                          "ev_class AS ruletable, ev_type, is_instead, "
7326                                                          "'O'::char AS ev_enabled "
7327                                                          "FROM pg_rewrite "
7328                                                          "ORDER BY oid");
7329         }
7330
7331         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7332
7333         ntups = PQntuples(res);
7334
7335         *numRules = ntups;
7336
7337         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7338
7339         i_tableoid = PQfnumber(res, "tableoid");
7340         i_oid = PQfnumber(res, "oid");
7341         i_rulename = PQfnumber(res, "rulename");
7342         i_ruletable = PQfnumber(res, "ruletable");
7343         i_ev_type = PQfnumber(res, "ev_type");
7344         i_is_instead = PQfnumber(res, "is_instead");
7345         i_ev_enabled = PQfnumber(res, "ev_enabled");
7346
7347         for (i = 0; i < ntups; i++)
7348         {
7349                 Oid                     ruletableoid;
7350
7351                 ruleinfo[i].dobj.objType = DO_RULE;
7352                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7353                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7354                 AssignDumpId(&ruleinfo[i].dobj);
7355                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7356                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7357                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7358                 if (ruleinfo[i].ruletable == NULL)
7359                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7360                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7361                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7362                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7363                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7364                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7365                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7366                 if (ruleinfo[i].ruletable)
7367                 {
7368                         /*
7369                          * If the table is a view or materialized view, force its ON
7370                          * SELECT rule to be sorted before the view itself --- this
7371                          * ensures that any dependencies for the rule affect the table's
7372                          * positioning. Other rules are forced to appear after their
7373                          * table.
7374                          */
7375                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7376                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7377                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7378                         {
7379                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7380                                                                         ruleinfo[i].dobj.dumpId);
7381                                 /* We'll merge the rule into CREATE VIEW, if possible */
7382                                 ruleinfo[i].separate = false;
7383                         }
7384                         else
7385                         {
7386                                 addObjectDependency(&ruleinfo[i].dobj,
7387                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7388                                 ruleinfo[i].separate = true;
7389                         }
7390                 }
7391                 else
7392                         ruleinfo[i].separate = true;
7393         }
7394
7395         PQclear(res);
7396
7397         destroyPQExpBuffer(query);
7398
7399         return ruleinfo;
7400 }
7401
7402 /*
7403  * getTriggers
7404  *        get information about every trigger on a dumpable table
7405  *
7406  * Note: trigger data is not returned directly to the caller, but it
7407  * does get entered into the DumpableObject tables.
7408  */
7409 void
7410 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7411 {
7412         int                     i,
7413                                 j;
7414         PQExpBuffer query = createPQExpBuffer();
7415         PGresult   *res;
7416         TriggerInfo *tginfo;
7417         int                     i_tableoid,
7418                                 i_oid,
7419                                 i_tgname,
7420                                 i_tgfname,
7421                                 i_tgtype,
7422                                 i_tgnargs,
7423                                 i_tgargs,
7424                                 i_tgisconstraint,
7425                                 i_tgconstrname,
7426                                 i_tgconstrrelid,
7427                                 i_tgconstrrelname,
7428                                 i_tgenabled,
7429                                 i_tgdeferrable,
7430                                 i_tginitdeferred,
7431                                 i_tgdef;
7432         int                     ntups;
7433
7434         for (i = 0; i < numTables; i++)
7435         {
7436                 TableInfo  *tbinfo = &tblinfo[i];
7437
7438                 if (!tbinfo->hastriggers ||
7439                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7440                         continue;
7441
7442                 if (g_verbose)
7443                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7444                                           tbinfo->dobj.namespace->dobj.name,
7445                                           tbinfo->dobj.name);
7446
7447                 resetPQExpBuffer(query);
7448                 if (fout->remoteVersion >= 90000)
7449                 {
7450                         /*
7451                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7452                          * could result in non-forward-compatible dumps of WHEN clauses
7453                          * due to under-parenthesization.
7454                          */
7455                         appendPQExpBuffer(query,
7456                                                           "SELECT tgname, "
7457                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7458                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7459                                                           "tgenabled, tableoid, oid "
7460                                                           "FROM pg_catalog.pg_trigger t "
7461                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7462                                                           "AND NOT tgisinternal",
7463                                                           tbinfo->dobj.catId.oid);
7464                 }
7465                 else if (fout->remoteVersion >= 80300)
7466                 {
7467                         /*
7468                          * We ignore triggers that are tied to a foreign-key constraint
7469                          */
7470                         appendPQExpBuffer(query,
7471                                                           "SELECT tgname, "
7472                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7473                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7474                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7475                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7476                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7477                                                           "FROM pg_catalog.pg_trigger t "
7478                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7479                                                           "AND tgconstraint = 0",
7480                                                           tbinfo->dobj.catId.oid);
7481                 }
7482                 else
7483                 {
7484                         /*
7485                          * We ignore triggers that are tied to a foreign-key constraint,
7486                          * but in these versions we have to grovel through pg_constraint
7487                          * to find out
7488                          */
7489                         appendPQExpBuffer(query,
7490                                                           "SELECT tgname, "
7491                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7492                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7493                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7494                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7495                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7496                                                           "FROM pg_catalog.pg_trigger t "
7497                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7498                                                           "AND (NOT tgisconstraint "
7499                                                           " OR NOT EXISTS"
7500                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7501                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7502                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7503                                                           tbinfo->dobj.catId.oid);
7504                 }
7505
7506                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7507
7508                 ntups = PQntuples(res);
7509
7510                 i_tableoid = PQfnumber(res, "tableoid");
7511                 i_oid = PQfnumber(res, "oid");
7512                 i_tgname = PQfnumber(res, "tgname");
7513                 i_tgfname = PQfnumber(res, "tgfname");
7514                 i_tgtype = PQfnumber(res, "tgtype");
7515                 i_tgnargs = PQfnumber(res, "tgnargs");
7516                 i_tgargs = PQfnumber(res, "tgargs");
7517                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7518                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7519                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7520                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7521                 i_tgenabled = PQfnumber(res, "tgenabled");
7522                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7523                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7524                 i_tgdef = PQfnumber(res, "tgdef");
7525
7526                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7527
7528                 tbinfo->numTriggers = ntups;
7529                 tbinfo->triggers = tginfo;
7530
7531                 for (j = 0; j < ntups; j++)
7532                 {
7533                         tginfo[j].dobj.objType = DO_TRIGGER;
7534                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7535                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7536                         AssignDumpId(&tginfo[j].dobj);
7537                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7538                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7539                         tginfo[j].tgtable = tbinfo;
7540                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7541                         if (i_tgdef >= 0)
7542                         {
7543                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7544
7545                                 /* remaining fields are not valid if we have tgdef */
7546                                 tginfo[j].tgfname = NULL;
7547                                 tginfo[j].tgtype = 0;
7548                                 tginfo[j].tgnargs = 0;
7549                                 tginfo[j].tgargs = NULL;
7550                                 tginfo[j].tgisconstraint = false;
7551                                 tginfo[j].tgdeferrable = false;
7552                                 tginfo[j].tginitdeferred = false;
7553                                 tginfo[j].tgconstrname = NULL;
7554                                 tginfo[j].tgconstrrelid = InvalidOid;
7555                                 tginfo[j].tgconstrrelname = NULL;
7556                         }
7557                         else
7558                         {
7559                                 tginfo[j].tgdef = NULL;
7560
7561                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7562                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7563                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7564                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7565                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7566                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7567                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7568
7569                                 if (tginfo[j].tgisconstraint)
7570                                 {
7571                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7572                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7573                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7574                                         {
7575                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7576                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7577                                                                                   tginfo[j].dobj.name,
7578                                                                                   tbinfo->dobj.name,
7579                                                                                   tginfo[j].tgconstrrelid);
7580                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7581                                         }
7582                                         else
7583                                                 tginfo[j].tgconstrrelname = NULL;
7584                                 }
7585                                 else
7586                                 {
7587                                         tginfo[j].tgconstrname = NULL;
7588                                         tginfo[j].tgconstrrelid = InvalidOid;
7589                                         tginfo[j].tgconstrrelname = NULL;
7590                                 }
7591                         }
7592                 }
7593
7594                 PQclear(res);
7595         }
7596
7597         destroyPQExpBuffer(query);
7598 }
7599
7600 /*
7601  * getEventTriggers
7602  *        get information about event triggers
7603  */
7604 EventTriggerInfo *
7605 getEventTriggers(Archive *fout, int *numEventTriggers)
7606 {
7607         int                     i;
7608         PQExpBuffer query;
7609         PGresult   *res;
7610         EventTriggerInfo *evtinfo;
7611         int                     i_tableoid,
7612                                 i_oid,
7613                                 i_evtname,
7614                                 i_evtevent,
7615                                 i_evtowner,
7616                                 i_evttags,
7617                                 i_evtfname,
7618                                 i_evtenabled;
7619         int                     ntups;
7620
7621         /* Before 9.3, there are no event triggers */
7622         if (fout->remoteVersion < 90300)
7623         {
7624                 *numEventTriggers = 0;
7625                 return NULL;
7626         }
7627
7628         query = createPQExpBuffer();
7629
7630         appendPQExpBuffer(query,
7631                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7632                                           "evtevent, (%s evtowner) AS evtowner, "
7633                                           "array_to_string(array("
7634                                           "select quote_literal(x) "
7635                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7636                                           "e.evtfoid::regproc as evtfname "
7637                                           "FROM pg_event_trigger e "
7638                                           "ORDER BY e.oid",
7639                                           username_subquery);
7640
7641         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7642
7643         ntups = PQntuples(res);
7644
7645         *numEventTriggers = ntups;
7646
7647         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7648
7649         i_tableoid = PQfnumber(res, "tableoid");
7650         i_oid = PQfnumber(res, "oid");
7651         i_evtname = PQfnumber(res, "evtname");
7652         i_evtevent = PQfnumber(res, "evtevent");
7653         i_evtowner = PQfnumber(res, "evtowner");
7654         i_evttags = PQfnumber(res, "evttags");
7655         i_evtfname = PQfnumber(res, "evtfname");
7656         i_evtenabled = PQfnumber(res, "evtenabled");
7657
7658         for (i = 0; i < ntups; i++)
7659         {
7660                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7661                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7662                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7663                 AssignDumpId(&evtinfo[i].dobj);
7664                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7665                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7666                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7667                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7668                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7669                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7670                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7671
7672                 /* Decide whether we want to dump it */
7673                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7674
7675                 /* Event Triggers do not currently have ACLs. */
7676                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7677         }
7678
7679         PQclear(res);
7680
7681         destroyPQExpBuffer(query);
7682
7683         return evtinfo;
7684 }
7685
7686 /*
7687  * getProcLangs
7688  *        get basic information about every procedural language in the system
7689  *
7690  * numProcLangs is set to the number of langs read in
7691  *
7692  * NB: this must run after getFuncs() because we assume we can do
7693  * findFuncByOid().
7694  */
7695 ProcLangInfo *
7696 getProcLangs(Archive *fout, int *numProcLangs)
7697 {
7698         DumpOptions *dopt = fout->dopt;
7699         PGresult   *res;
7700         int                     ntups;
7701         int                     i;
7702         PQExpBuffer query = createPQExpBuffer();
7703         ProcLangInfo *planginfo;
7704         int                     i_tableoid;
7705         int                     i_oid;
7706         int                     i_lanname;
7707         int                     i_lanpltrusted;
7708         int                     i_lanplcallfoid;
7709         int                     i_laninline;
7710         int                     i_lanvalidator;
7711         int                     i_lanacl;
7712         int                     i_rlanacl;
7713         int                     i_initlanacl;
7714         int                     i_initrlanacl;
7715         int                     i_lanowner;
7716
7717         if (fout->remoteVersion >= 90600)
7718         {
7719                 PQExpBuffer acl_subquery = createPQExpBuffer();
7720                 PQExpBuffer racl_subquery = createPQExpBuffer();
7721                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7722                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7723
7724                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7725                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7726                                                 dopt->binary_upgrade);
7727
7728                 /* pg_language has a laninline column */
7729                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7730                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7731                                                   "l.laninline, l.lanvalidator, "
7732                                                   "%s AS lanacl, "
7733                                                   "%s AS rlanacl, "
7734                                                   "%s AS initlanacl, "
7735                                                   "%s AS initrlanacl, "
7736                                                   "(%s l.lanowner) AS lanowner "
7737                                                   "FROM pg_language l "
7738                                                   "LEFT JOIN pg_init_privs pip ON "
7739                                                   "(l.oid = pip.objoid "
7740                                                   "AND pip.classoid = 'pg_language'::regclass "
7741                                                   "AND pip.objsubid = 0) "
7742                                                   "WHERE l.lanispl "
7743                                                   "ORDER BY l.oid",
7744                                                   acl_subquery->data,
7745                                                   racl_subquery->data,
7746                                                   initacl_subquery->data,
7747                                                   initracl_subquery->data,
7748                                                   username_subquery);
7749
7750                 destroyPQExpBuffer(acl_subquery);
7751                 destroyPQExpBuffer(racl_subquery);
7752                 destroyPQExpBuffer(initacl_subquery);
7753                 destroyPQExpBuffer(initracl_subquery);
7754         }
7755         else if (fout->remoteVersion >= 90000)
7756         {
7757                 /* pg_language has a laninline column */
7758                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7759                                                   "lanname, lanpltrusted, lanplcallfoid, "
7760                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7761                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7762                                                   "(%s lanowner) AS lanowner "
7763                                                   "FROM pg_language "
7764                                                   "WHERE lanispl "
7765                                                   "ORDER BY oid",
7766                                                   username_subquery);
7767         }
7768         else if (fout->remoteVersion >= 80300)
7769         {
7770                 /* pg_language has a lanowner column */
7771                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7772                                                   "lanname, lanpltrusted, lanplcallfoid, "
7773                                                   "0 AS laninline, lanvalidator, lanacl, "
7774                                                   "NULL AS rlanacl, "
7775                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7776                                                   "(%s lanowner) AS lanowner "
7777                                                   "FROM pg_language "
7778                                                   "WHERE lanispl "
7779                                                   "ORDER BY oid",
7780                                                   username_subquery);
7781         }
7782         else if (fout->remoteVersion >= 80100)
7783         {
7784                 /* Languages are owned by the bootstrap superuser, OID 10 */
7785                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7786                                                   "lanname, lanpltrusted, lanplcallfoid, "
7787                                                   "0 AS laninline, lanvalidator, lanacl, "
7788                                                   "NULL AS rlanacl, "
7789                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7790                                                   "(%s '10') AS lanowner "
7791                                                   "FROM pg_language "
7792                                                   "WHERE lanispl "
7793                                                   "ORDER BY oid",
7794                                                   username_subquery);
7795         }
7796         else
7797         {
7798                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7799                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7800                                                   "lanname, lanpltrusted, lanplcallfoid, "
7801                                                   "0 AS laninline, lanvalidator, lanacl, "
7802                                                   "NULL AS rlanacl, "
7803                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7804                                                   "(%s '1') AS lanowner "
7805                                                   "FROM pg_language "
7806                                                   "WHERE lanispl "
7807                                                   "ORDER BY oid",
7808                                                   username_subquery);
7809         }
7810
7811         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7812
7813         ntups = PQntuples(res);
7814
7815         *numProcLangs = ntups;
7816
7817         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7818
7819         i_tableoid = PQfnumber(res, "tableoid");
7820         i_oid = PQfnumber(res, "oid");
7821         i_lanname = PQfnumber(res, "lanname");
7822         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7823         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7824         i_laninline = PQfnumber(res, "laninline");
7825         i_lanvalidator = PQfnumber(res, "lanvalidator");
7826         i_lanacl = PQfnumber(res, "lanacl");
7827         i_rlanacl = PQfnumber(res, "rlanacl");
7828         i_initlanacl = PQfnumber(res, "initlanacl");
7829         i_initrlanacl = PQfnumber(res, "initrlanacl");
7830         i_lanowner = PQfnumber(res, "lanowner");
7831
7832         for (i = 0; i < ntups; i++)
7833         {
7834                 planginfo[i].dobj.objType = DO_PROCLANG;
7835                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7836                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7837                 AssignDumpId(&planginfo[i].dobj);
7838
7839                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7840                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7841                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7842                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7843                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7844                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7845                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7846                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7847                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7848                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7849
7850                 /* Decide whether we want to dump it */
7851                 selectDumpableProcLang(&(planginfo[i]), fout);
7852
7853                 /* Do not try to dump ACL if no ACL exists. */
7854                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7855                         PQgetisnull(res, i, i_initlanacl) &&
7856                         PQgetisnull(res, i, i_initrlanacl))
7857                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7858         }
7859
7860         PQclear(res);
7861
7862         destroyPQExpBuffer(query);
7863
7864         return planginfo;
7865 }
7866
7867 /*
7868  * getCasts
7869  *        get basic information about every cast in the system
7870  *
7871  * numCasts is set to the number of casts read in
7872  */
7873 CastInfo *
7874 getCasts(Archive *fout, int *numCasts)
7875 {
7876         PGresult   *res;
7877         int                     ntups;
7878         int                     i;
7879         PQExpBuffer query = createPQExpBuffer();
7880         CastInfo   *castinfo;
7881         int                     i_tableoid;
7882         int                     i_oid;
7883         int                     i_castsource;
7884         int                     i_casttarget;
7885         int                     i_castfunc;
7886         int                     i_castcontext;
7887         int                     i_castmethod;
7888
7889         if (fout->remoteVersion >= 80400)
7890         {
7891                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7892                                                          "castsource, casttarget, castfunc, castcontext, "
7893                                                          "castmethod "
7894                                                          "FROM pg_cast ORDER BY 3,4");
7895         }
7896         else
7897         {
7898                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7899                                                          "castsource, casttarget, castfunc, castcontext, "
7900                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7901                                                          "FROM pg_cast ORDER BY 3,4");
7902         }
7903
7904         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7905
7906         ntups = PQntuples(res);
7907
7908         *numCasts = ntups;
7909
7910         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7911
7912         i_tableoid = PQfnumber(res, "tableoid");
7913         i_oid = PQfnumber(res, "oid");
7914         i_castsource = PQfnumber(res, "castsource");
7915         i_casttarget = PQfnumber(res, "casttarget");
7916         i_castfunc = PQfnumber(res, "castfunc");
7917         i_castcontext = PQfnumber(res, "castcontext");
7918         i_castmethod = PQfnumber(res, "castmethod");
7919
7920         for (i = 0; i < ntups; i++)
7921         {
7922                 PQExpBufferData namebuf;
7923                 TypeInfo   *sTypeInfo;
7924                 TypeInfo   *tTypeInfo;
7925
7926                 castinfo[i].dobj.objType = DO_CAST;
7927                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7928                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7929                 AssignDumpId(&castinfo[i].dobj);
7930                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7931                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7932                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7933                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7934                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7935
7936                 /*
7937                  * Try to name cast as concatenation of typnames.  This is only used
7938                  * for purposes of sorting.  If we fail to find either type, the name
7939                  * will be an empty string.
7940                  */
7941                 initPQExpBuffer(&namebuf);
7942                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
7943                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7944                 if (sTypeInfo && tTypeInfo)
7945                         appendPQExpBuffer(&namebuf, "%s %s",
7946                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7947                 castinfo[i].dobj.name = namebuf.data;
7948
7949                 /* Decide whether we want to dump it */
7950                 selectDumpableCast(&(castinfo[i]), fout);
7951
7952                 /* Casts do not currently have ACLs. */
7953                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7954         }
7955
7956         PQclear(res);
7957
7958         destroyPQExpBuffer(query);
7959
7960         return castinfo;
7961 }
7962
7963 static char *
7964 get_language_name(Archive *fout, Oid langid)
7965 {
7966         PQExpBuffer query;
7967         PGresult   *res;
7968         char       *lanname;
7969
7970         query = createPQExpBuffer();
7971         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
7972         res = ExecuteSqlQueryForSingleRow(fout, query->data);
7973         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
7974         destroyPQExpBuffer(query);
7975         PQclear(res);
7976
7977         return lanname;
7978 }
7979
7980 /*
7981  * getTransforms
7982  *        get basic information about every transform in the system
7983  *
7984  * numTransforms is set to the number of transforms read in
7985  */
7986 TransformInfo *
7987 getTransforms(Archive *fout, int *numTransforms)
7988 {
7989         PGresult   *res;
7990         int                     ntups;
7991         int                     i;
7992         PQExpBuffer query;
7993         TransformInfo *transforminfo;
7994         int                     i_tableoid;
7995         int                     i_oid;
7996         int                     i_trftype;
7997         int                     i_trflang;
7998         int                     i_trffromsql;
7999         int                     i_trftosql;
8000
8001         /* Transforms didn't exist pre-9.5 */
8002         if (fout->remoteVersion < 90500)
8003         {
8004                 *numTransforms = 0;
8005                 return NULL;
8006         }
8007
8008         query = createPQExpBuffer();
8009
8010         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8011                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8012                                           "FROM pg_transform "
8013                                           "ORDER BY 3,4");
8014
8015         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8016
8017         ntups = PQntuples(res);
8018
8019         *numTransforms = ntups;
8020
8021         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8022
8023         i_tableoid = PQfnumber(res, "tableoid");
8024         i_oid = PQfnumber(res, "oid");
8025         i_trftype = PQfnumber(res, "trftype");
8026         i_trflang = PQfnumber(res, "trflang");
8027         i_trffromsql = PQfnumber(res, "trffromsql");
8028         i_trftosql = PQfnumber(res, "trftosql");
8029
8030         for (i = 0; i < ntups; i++)
8031         {
8032                 PQExpBufferData namebuf;
8033                 TypeInfo   *typeInfo;
8034                 char       *lanname;
8035
8036                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8037                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8038                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8039                 AssignDumpId(&transforminfo[i].dobj);
8040                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8041                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8042                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8043                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8044
8045                 /*
8046                  * Try to name transform as concatenation of type and language name.
8047                  * This is only used for purposes of sorting.  If we fail to find
8048                  * either, the name will be an empty string.
8049                  */
8050                 initPQExpBuffer(&namebuf);
8051                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8052                 lanname = get_language_name(fout, transforminfo[i].trflang);
8053                 if (typeInfo && lanname)
8054                         appendPQExpBuffer(&namebuf, "%s %s",
8055                                                           typeInfo->dobj.name, lanname);
8056                 transforminfo[i].dobj.name = namebuf.data;
8057                 free(lanname);
8058
8059                 /* Decide whether we want to dump it */
8060                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8061         }
8062
8063         PQclear(res);
8064
8065         destroyPQExpBuffer(query);
8066
8067         return transforminfo;
8068 }
8069
8070 /*
8071  * getTableAttrs -
8072  *        for each interesting table, read info about its attributes
8073  *        (names, types, default values, CHECK constraints, etc)
8074  *
8075  * This is implemented in a very inefficient way right now, looping
8076  * through the tblinfo and doing a join per table to find the attrs and their
8077  * types.  However, because we want type names and so forth to be named
8078  * relative to the schema of each table, we couldn't do it in just one
8079  * query.  (Maybe one query per schema?)
8080  *
8081  *      modifies tblinfo
8082  */
8083 void
8084 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8085 {
8086         DumpOptions *dopt = fout->dopt;
8087         int                     i,
8088                                 j;
8089         PQExpBuffer q = createPQExpBuffer();
8090         int                     i_attnum;
8091         int                     i_attname;
8092         int                     i_atttypname;
8093         int                     i_atttypmod;
8094         int                     i_attstattarget;
8095         int                     i_attstorage;
8096         int                     i_typstorage;
8097         int                     i_attnotnull;
8098         int                     i_atthasdef;
8099         int                     i_attidentity;
8100         int                     i_attisdropped;
8101         int                     i_attlen;
8102         int                     i_attalign;
8103         int                     i_attislocal;
8104         int                     i_attoptions;
8105         int                     i_attcollation;
8106         int                     i_attfdwoptions;
8107         int                     i_attmissingval;
8108         PGresult   *res;
8109         int                     ntups;
8110         bool            hasdefaults;
8111
8112         for (i = 0; i < numTables; i++)
8113         {
8114                 TableInfo  *tbinfo = &tblinfo[i];
8115
8116                 /* Don't bother to collect info for sequences */
8117                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8118                         continue;
8119
8120                 /* Don't bother with uninteresting tables, either */
8121                 if (!tbinfo->interesting)
8122                         continue;
8123
8124                 /* find all the user attributes and their types */
8125
8126                 /*
8127                  * we must read the attribute names in attribute number order! because
8128                  * we will use the attnum to index into the attnames array later.
8129                  */
8130                 if (g_verbose)
8131                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8132                                           tbinfo->dobj.namespace->dobj.name,
8133                                           tbinfo->dobj.name);
8134
8135                 resetPQExpBuffer(q);
8136
8137                 appendPQExpBuffer(q,
8138                                                   "SELECT\n"
8139                                                   "a.attnum,\n"
8140                                                   "a.attname,\n"
8141                                                   "a.atttypmod,\n"
8142                                                   "a.attstattarget,\n"
8143                                                   "a.attstorage,\n"
8144                                                   "t.typstorage,\n"
8145                                                   "a.attnotnull,\n"
8146                                                   "a.atthasdef,\n"
8147                                                   "a.attisdropped,\n"
8148                                                   "a.attlen,\n"
8149                                                   "a.attalign,\n"
8150                                                   "a.attislocal,\n"
8151                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8152
8153                 if (fout->remoteVersion >= 110000)
8154                         appendPQExpBuffer(q,
8155                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8156                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8157                 else
8158                         appendPQExpBuffer(q,
8159                                                           "NULL AS attmissingval,\n");
8160
8161                 if (fout->remoteVersion >= 100000)
8162                         appendPQExpBuffer(q,
8163                                                           "a.attidentity,\n");
8164                 else
8165                         appendPQExpBuffer(q,
8166                                                           "'' AS attidentity,\n");
8167
8168                 if (fout->remoteVersion >= 90200)
8169                         appendPQExpBuffer(q,
8170                                                           "pg_catalog.array_to_string(ARRAY("
8171                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8172                                                           "' ' || pg_catalog.quote_literal(option_value) "
8173                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8174                                                           "ORDER BY option_name"
8175                                                           "), E',\n    ') AS attfdwoptions,\n");
8176                 else
8177                         appendPQExpBuffer(q,
8178                                                           "'' AS attfdwoptions,\n");
8179
8180                 if (fout->remoteVersion >= 90100)
8181                 {
8182                         /*
8183                          * Since we only want to dump COLLATE clauses for attributes whose
8184                          * collation is different from their type's default, we use a CASE
8185                          * here to suppress uninteresting attcollations cheaply.
8186                          */
8187                         appendPQExpBuffer(q,
8188                                                           "CASE WHEN a.attcollation <> t.typcollation "
8189                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8190                 }
8191                 else
8192                         appendPQExpBuffer(q,
8193                                                           "0 AS attcollation,\n");
8194
8195                 if (fout->remoteVersion >= 90000)
8196                         appendPQExpBuffer(q,
8197                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8198                 else
8199                         appendPQExpBuffer(q,
8200                                                           "'' AS attoptions\n");
8201
8202                 /* need left join here to not fail on dropped columns ... */
8203                 appendPQExpBuffer(q,
8204                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8205                                                   "ON a.atttypid = t.oid\n"
8206                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8207                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8208                                                   "ORDER BY a.attnum",
8209                                                   tbinfo->dobj.catId.oid);
8210
8211                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8212
8213                 ntups = PQntuples(res);
8214
8215                 i_attnum = PQfnumber(res, "attnum");
8216                 i_attname = PQfnumber(res, "attname");
8217                 i_atttypname = PQfnumber(res, "atttypname");
8218                 i_atttypmod = PQfnumber(res, "atttypmod");
8219                 i_attstattarget = PQfnumber(res, "attstattarget");
8220                 i_attstorage = PQfnumber(res, "attstorage");
8221                 i_typstorage = PQfnumber(res, "typstorage");
8222                 i_attnotnull = PQfnumber(res, "attnotnull");
8223                 i_atthasdef = PQfnumber(res, "atthasdef");
8224                 i_attidentity = PQfnumber(res, "attidentity");
8225                 i_attisdropped = PQfnumber(res, "attisdropped");
8226                 i_attlen = PQfnumber(res, "attlen");
8227                 i_attalign = PQfnumber(res, "attalign");
8228                 i_attislocal = PQfnumber(res, "attislocal");
8229                 i_attoptions = PQfnumber(res, "attoptions");
8230                 i_attcollation = PQfnumber(res, "attcollation");
8231                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8232                 i_attmissingval = PQfnumber(res, "attmissingval");
8233
8234                 tbinfo->numatts = ntups;
8235                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8236                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8237                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8238                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8239                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8240                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8241                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8242                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8243                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8244                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8245                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8246                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8247                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8248                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8249                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8250                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8251                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8252                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8253                 hasdefaults = false;
8254
8255                 for (j = 0; j < ntups; j++)
8256                 {
8257                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8258                                 exit_horribly(NULL,
8259                                                           "invalid column numbering in table \"%s\"\n",
8260                                                           tbinfo->dobj.name);
8261                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8262                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8263                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8264                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8265                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8266                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8267                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8268                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8269                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8270                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8271                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8272                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8273                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8274                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8275                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8276                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8277                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8278                         tbinfo->attrdefs[j] = NULL; /* fix below */
8279                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8280                                 hasdefaults = true;
8281                         /* these flags will be set in flagInhAttrs() */
8282                         tbinfo->inhNotNull[j] = false;
8283                 }
8284
8285                 PQclear(res);
8286
8287                 /*
8288                  * Get info about column defaults
8289                  */
8290                 if (hasdefaults)
8291                 {
8292                         AttrDefInfo *attrdefs;
8293                         int                     numDefaults;
8294
8295                         if (g_verbose)
8296                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8297                                                   tbinfo->dobj.namespace->dobj.name,
8298                                                   tbinfo->dobj.name);
8299
8300                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8301                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8302                                                           "FROM pg_catalog.pg_attrdef "
8303                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8304                                                           tbinfo->dobj.catId.oid);
8305
8306                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8307
8308                         numDefaults = PQntuples(res);
8309                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8310
8311                         for (j = 0; j < numDefaults; j++)
8312                         {
8313                                 int                     adnum;
8314
8315                                 adnum = atoi(PQgetvalue(res, j, 2));
8316
8317                                 if (adnum <= 0 || adnum > ntups)
8318                                         exit_horribly(NULL,
8319                                                                   "invalid adnum value %d for table \"%s\"\n",
8320                                                                   adnum, tbinfo->dobj.name);
8321
8322                                 /*
8323                                  * dropped columns shouldn't have defaults, but just in case,
8324                                  * ignore 'em
8325                                  */
8326                                 if (tbinfo->attisdropped[adnum - 1])
8327                                         continue;
8328
8329                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8330                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8331                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8332                                 AssignDumpId(&attrdefs[j].dobj);
8333                                 attrdefs[j].adtable = tbinfo;
8334                                 attrdefs[j].adnum = adnum;
8335                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8336
8337                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8338                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8339
8340                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8341
8342                                 /*
8343                                  * Defaults on a VIEW must always be dumped as separate ALTER
8344                                  * TABLE commands.  Defaults on regular tables are dumped as
8345                                  * part of the CREATE TABLE if possible, which it won't be if
8346                                  * the column is not going to be emitted explicitly.
8347                                  */
8348                                 if (tbinfo->relkind == RELKIND_VIEW)
8349                                 {
8350                                         attrdefs[j].separate = true;
8351                                 }
8352                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8353                                 {
8354                                         /* column will be suppressed, print default separately */
8355                                         attrdefs[j].separate = true;
8356                                 }
8357                                 else
8358                                 {
8359                                         attrdefs[j].separate = false;
8360
8361                                         /*
8362                                          * Mark the default as needing to appear before the table,
8363                                          * so that any dependencies it has must be emitted before
8364                                          * the CREATE TABLE.  If this is not possible, we'll
8365                                          * change to "separate" mode while sorting dependencies.
8366                                          */
8367                                         addObjectDependency(&tbinfo->dobj,
8368                                                                                 attrdefs[j].dobj.dumpId);
8369                                 }
8370
8371                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8372                         }
8373                         PQclear(res);
8374                 }
8375
8376                 /*
8377                  * Get info about table CHECK constraints
8378                  */
8379                 if (tbinfo->ncheck > 0)
8380                 {
8381                         ConstraintInfo *constrs;
8382                         int                     numConstrs;
8383
8384                         if (g_verbose)
8385                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8386                                                   tbinfo->dobj.namespace->dobj.name,
8387                                                   tbinfo->dobj.name);
8388
8389                         resetPQExpBuffer(q);
8390                         if (fout->remoteVersion >= 90200)
8391                         {
8392                                 /*
8393                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8394                                  * but it wasn't ever false for check constraints until 9.2).
8395                                  */
8396                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8397                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8398                                                                   "conislocal, convalidated "
8399                                                                   "FROM pg_catalog.pg_constraint "
8400                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8401                                                                   "   AND contype = 'c' "
8402                                                                   "ORDER BY conname",
8403                                                                   tbinfo->dobj.catId.oid);
8404                         }
8405                         else if (fout->remoteVersion >= 80400)
8406                         {
8407                                 /* conislocal is new in 8.4 */
8408                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8409                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8410                                                                   "conislocal, true AS convalidated "
8411                                                                   "FROM pg_catalog.pg_constraint "
8412                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8413                                                                   "   AND contype = 'c' "
8414                                                                   "ORDER BY conname",
8415                                                                   tbinfo->dobj.catId.oid);
8416                         }
8417                         else
8418                         {
8419                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8420                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8421                                                                   "true AS conislocal, true AS convalidated "
8422                                                                   "FROM pg_catalog.pg_constraint "
8423                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8424                                                                   "   AND contype = 'c' "
8425                                                                   "ORDER BY conname",
8426                                                                   tbinfo->dobj.catId.oid);
8427                         }
8428
8429                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8430
8431                         numConstrs = PQntuples(res);
8432                         if (numConstrs != tbinfo->ncheck)
8433                         {
8434                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8435                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8436                                                                                  tbinfo->ncheck),
8437                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8438                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8439                                 exit_nicely(1);
8440                         }
8441
8442                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8443                         tbinfo->checkexprs = constrs;
8444
8445                         for (j = 0; j < numConstrs; j++)
8446                         {
8447                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8448
8449                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8450                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8451                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8452                                 AssignDumpId(&constrs[j].dobj);
8453                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8454                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8455                                 constrs[j].contable = tbinfo;
8456                                 constrs[j].condomain = NULL;
8457                                 constrs[j].contype = 'c';
8458                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8459                                 constrs[j].confrelid = InvalidOid;
8460                                 constrs[j].conindex = 0;
8461                                 constrs[j].condeferrable = false;
8462                                 constrs[j].condeferred = false;
8463                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8464
8465                                 /*
8466                                  * An unvalidated constraint needs to be dumped separately, so
8467                                  * that potentially-violating existing data is loaded before
8468                                  * the constraint.
8469                                  */
8470                                 constrs[j].separate = !validated;
8471
8472                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8473
8474                                 /*
8475                                  * Mark the constraint as needing to appear before the table
8476                                  * --- this is so that any other dependencies of the
8477                                  * constraint will be emitted before we try to create the
8478                                  * table.  If the constraint is to be dumped separately, it
8479                                  * will be dumped after data is loaded anyway, so don't do it.
8480                                  * (There's an automatic dependency in the opposite direction
8481                                  * anyway, so don't need to add one manually here.)
8482                                  */
8483                                 if (!constrs[j].separate)
8484                                         addObjectDependency(&tbinfo->dobj,
8485                                                                                 constrs[j].dobj.dumpId);
8486
8487                                 /*
8488                                  * If the constraint is inherited, this will be detected later
8489                                  * (in pre-8.4 databases).  We also detect later if the
8490                                  * constraint must be split out from the table definition.
8491                                  */
8492                         }
8493                         PQclear(res);
8494                 }
8495         }
8496
8497         destroyPQExpBuffer(q);
8498 }
8499
8500 /*
8501  * Test whether a column should be printed as part of table's CREATE TABLE.
8502  * Column number is zero-based.
8503  *
8504  * Normally this is always true, but it's false for dropped columns, as well
8505  * as those that were inherited without any local definition.  (If we print
8506  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8507  * However, in binary_upgrade mode, we must print all such columns anyway and
8508  * fix the attislocal/attisdropped state later, so as to keep control of the
8509  * physical column order.
8510  *
8511  * This function exists because there are scattered nonobvious places that
8512  * must be kept in sync with this decision.
8513  */
8514 bool
8515 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8516 {
8517         if (dopt->binary_upgrade)
8518                 return true;
8519         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8520 }
8521
8522
8523 /*
8524  * getTSParsers:
8525  *        read all text search parsers in the system catalogs and return them
8526  *        in the TSParserInfo* structure
8527  *
8528  *      numTSParsers is set to the number of parsers read in
8529  */
8530 TSParserInfo *
8531 getTSParsers(Archive *fout, int *numTSParsers)
8532 {
8533         PGresult   *res;
8534         int                     ntups;
8535         int                     i;
8536         PQExpBuffer query;
8537         TSParserInfo *prsinfo;
8538         int                     i_tableoid;
8539         int                     i_oid;
8540         int                     i_prsname;
8541         int                     i_prsnamespace;
8542         int                     i_prsstart;
8543         int                     i_prstoken;
8544         int                     i_prsend;
8545         int                     i_prsheadline;
8546         int                     i_prslextype;
8547
8548         /* Before 8.3, there is no built-in text search support */
8549         if (fout->remoteVersion < 80300)
8550         {
8551                 *numTSParsers = 0;
8552                 return NULL;
8553         }
8554
8555         query = createPQExpBuffer();
8556
8557         /*
8558          * find all text search objects, including builtin ones; we filter out
8559          * system-defined objects at dump-out time.
8560          */
8561
8562         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8563                                                  "prsstart::oid, prstoken::oid, "
8564                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8565                                                  "FROM pg_ts_parser");
8566
8567         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8568
8569         ntups = PQntuples(res);
8570         *numTSParsers = ntups;
8571
8572         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8573
8574         i_tableoid = PQfnumber(res, "tableoid");
8575         i_oid = PQfnumber(res, "oid");
8576         i_prsname = PQfnumber(res, "prsname");
8577         i_prsnamespace = PQfnumber(res, "prsnamespace");
8578         i_prsstart = PQfnumber(res, "prsstart");
8579         i_prstoken = PQfnumber(res, "prstoken");
8580         i_prsend = PQfnumber(res, "prsend");
8581         i_prsheadline = PQfnumber(res, "prsheadline");
8582         i_prslextype = PQfnumber(res, "prslextype");
8583
8584         for (i = 0; i < ntups; i++)
8585         {
8586                 prsinfo[i].dobj.objType = DO_TSPARSER;
8587                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8588                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8589                 AssignDumpId(&prsinfo[i].dobj);
8590                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8591                 prsinfo[i].dobj.namespace =
8592                         findNamespace(fout,
8593                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8594                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8595                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8596                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8597                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8598                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8599
8600                 /* Decide whether we want to dump it */
8601                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8602
8603                 /* Text Search Parsers do not currently have ACLs. */
8604                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8605         }
8606
8607         PQclear(res);
8608
8609         destroyPQExpBuffer(query);
8610
8611         return prsinfo;
8612 }
8613
8614 /*
8615  * getTSDictionaries:
8616  *        read all text search dictionaries in the system catalogs and return them
8617  *        in the TSDictInfo* structure
8618  *
8619  *      numTSDicts is set to the number of dictionaries read in
8620  */
8621 TSDictInfo *
8622 getTSDictionaries(Archive *fout, int *numTSDicts)
8623 {
8624         PGresult   *res;
8625         int                     ntups;
8626         int                     i;
8627         PQExpBuffer query;
8628         TSDictInfo *dictinfo;
8629         int                     i_tableoid;
8630         int                     i_oid;
8631         int                     i_dictname;
8632         int                     i_dictnamespace;
8633         int                     i_rolname;
8634         int                     i_dicttemplate;
8635         int                     i_dictinitoption;
8636
8637         /* Before 8.3, there is no built-in text search support */
8638         if (fout->remoteVersion < 80300)
8639         {
8640                 *numTSDicts = 0;
8641                 return NULL;
8642         }
8643
8644         query = createPQExpBuffer();
8645
8646         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8647                                           "dictnamespace, (%s dictowner) AS rolname, "
8648                                           "dicttemplate, dictinitoption "
8649                                           "FROM pg_ts_dict",
8650                                           username_subquery);
8651
8652         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8653
8654         ntups = PQntuples(res);
8655         *numTSDicts = ntups;
8656
8657         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8658
8659         i_tableoid = PQfnumber(res, "tableoid");
8660         i_oid = PQfnumber(res, "oid");
8661         i_dictname = PQfnumber(res, "dictname");
8662         i_dictnamespace = PQfnumber(res, "dictnamespace");
8663         i_rolname = PQfnumber(res, "rolname");
8664         i_dictinitoption = PQfnumber(res, "dictinitoption");
8665         i_dicttemplate = PQfnumber(res, "dicttemplate");
8666
8667         for (i = 0; i < ntups; i++)
8668         {
8669                 dictinfo[i].dobj.objType = DO_TSDICT;
8670                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8671                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8672                 AssignDumpId(&dictinfo[i].dobj);
8673                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8674                 dictinfo[i].dobj.namespace =
8675                         findNamespace(fout,
8676                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8677                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8678                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8679                 if (PQgetisnull(res, i, i_dictinitoption))
8680                         dictinfo[i].dictinitoption = NULL;
8681                 else
8682                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8683
8684                 /* Decide whether we want to dump it */
8685                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8686
8687                 /* Text Search Dictionaries do not currently have ACLs. */
8688                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8689         }
8690
8691         PQclear(res);
8692
8693         destroyPQExpBuffer(query);
8694
8695         return dictinfo;
8696 }
8697
8698 /*
8699  * getTSTemplates:
8700  *        read all text search templates in the system catalogs and return them
8701  *        in the TSTemplateInfo* structure
8702  *
8703  *      numTSTemplates is set to the number of templates read in
8704  */
8705 TSTemplateInfo *
8706 getTSTemplates(Archive *fout, int *numTSTemplates)
8707 {
8708         PGresult   *res;
8709         int                     ntups;
8710         int                     i;
8711         PQExpBuffer query;
8712         TSTemplateInfo *tmplinfo;
8713         int                     i_tableoid;
8714         int                     i_oid;
8715         int                     i_tmplname;
8716         int                     i_tmplnamespace;
8717         int                     i_tmplinit;
8718         int                     i_tmpllexize;
8719
8720         /* Before 8.3, there is no built-in text search support */
8721         if (fout->remoteVersion < 80300)
8722         {
8723                 *numTSTemplates = 0;
8724                 return NULL;
8725         }
8726
8727         query = createPQExpBuffer();
8728
8729         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8730                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8731                                                  "FROM pg_ts_template");
8732
8733         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8734
8735         ntups = PQntuples(res);
8736         *numTSTemplates = ntups;
8737
8738         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8739
8740         i_tableoid = PQfnumber(res, "tableoid");
8741         i_oid = PQfnumber(res, "oid");
8742         i_tmplname = PQfnumber(res, "tmplname");
8743         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8744         i_tmplinit = PQfnumber(res, "tmplinit");
8745         i_tmpllexize = PQfnumber(res, "tmpllexize");
8746
8747         for (i = 0; i < ntups; i++)
8748         {
8749                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8750                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8751                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8752                 AssignDumpId(&tmplinfo[i].dobj);
8753                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8754                 tmplinfo[i].dobj.namespace =
8755                         findNamespace(fout,
8756                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8757                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8758                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8759
8760                 /* Decide whether we want to dump it */
8761                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8762
8763                 /* Text Search Templates do not currently have ACLs. */
8764                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8765         }
8766
8767         PQclear(res);
8768
8769         destroyPQExpBuffer(query);
8770
8771         return tmplinfo;
8772 }
8773
8774 /*
8775  * getTSConfigurations:
8776  *        read all text search configurations in the system catalogs and return
8777  *        them in the TSConfigInfo* structure
8778  *
8779  *      numTSConfigs is set to the number of configurations read in
8780  */
8781 TSConfigInfo *
8782 getTSConfigurations(Archive *fout, int *numTSConfigs)
8783 {
8784         PGresult   *res;
8785         int                     ntups;
8786         int                     i;
8787         PQExpBuffer query;
8788         TSConfigInfo *cfginfo;
8789         int                     i_tableoid;
8790         int                     i_oid;
8791         int                     i_cfgname;
8792         int                     i_cfgnamespace;
8793         int                     i_rolname;
8794         int                     i_cfgparser;
8795
8796         /* Before 8.3, there is no built-in text search support */
8797         if (fout->remoteVersion < 80300)
8798         {
8799                 *numTSConfigs = 0;
8800                 return NULL;
8801         }
8802
8803         query = createPQExpBuffer();
8804
8805         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8806                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8807                                           "FROM pg_ts_config",
8808                                           username_subquery);
8809
8810         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8811
8812         ntups = PQntuples(res);
8813         *numTSConfigs = ntups;
8814
8815         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8816
8817         i_tableoid = PQfnumber(res, "tableoid");
8818         i_oid = PQfnumber(res, "oid");
8819         i_cfgname = PQfnumber(res, "cfgname");
8820         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8821         i_rolname = PQfnumber(res, "rolname");
8822         i_cfgparser = PQfnumber(res, "cfgparser");
8823
8824         for (i = 0; i < ntups; i++)
8825         {
8826                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8827                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8828                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8829                 AssignDumpId(&cfginfo[i].dobj);
8830                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8831                 cfginfo[i].dobj.namespace =
8832                         findNamespace(fout,
8833                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8834                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8835                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8836
8837                 /* Decide whether we want to dump it */
8838                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8839
8840                 /* Text Search Configurations do not currently have ACLs. */
8841                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8842         }
8843
8844         PQclear(res);
8845
8846         destroyPQExpBuffer(query);
8847
8848         return cfginfo;
8849 }
8850
8851 /*
8852  * getForeignDataWrappers:
8853  *        read all foreign-data wrappers in the system catalogs and return
8854  *        them in the FdwInfo* structure
8855  *
8856  *      numForeignDataWrappers is set to the number of fdws read in
8857  */
8858 FdwInfo *
8859 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8860 {
8861         DumpOptions *dopt = fout->dopt;
8862         PGresult   *res;
8863         int                     ntups;
8864         int                     i;
8865         PQExpBuffer query;
8866         FdwInfo    *fdwinfo;
8867         int                     i_tableoid;
8868         int                     i_oid;
8869         int                     i_fdwname;
8870         int                     i_rolname;
8871         int                     i_fdwhandler;
8872         int                     i_fdwvalidator;
8873         int                     i_fdwacl;
8874         int                     i_rfdwacl;
8875         int                     i_initfdwacl;
8876         int                     i_initrfdwacl;
8877         int                     i_fdwoptions;
8878
8879         /* Before 8.4, there are no foreign-data wrappers */
8880         if (fout->remoteVersion < 80400)
8881         {
8882                 *numForeignDataWrappers = 0;
8883                 return NULL;
8884         }
8885
8886         query = createPQExpBuffer();
8887
8888         if (fout->remoteVersion >= 90600)
8889         {
8890                 PQExpBuffer acl_subquery = createPQExpBuffer();
8891                 PQExpBuffer racl_subquery = createPQExpBuffer();
8892                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8893                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8894
8895                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8896                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8897                                                 dopt->binary_upgrade);
8898
8899                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8900                                                   "(%s f.fdwowner) AS rolname, "
8901                                                   "f.fdwhandler::pg_catalog.regproc, "
8902                                                   "f.fdwvalidator::pg_catalog.regproc, "
8903                                                   "%s AS fdwacl, "
8904                                                   "%s AS rfdwacl, "
8905                                                   "%s AS initfdwacl, "
8906                                                   "%s AS initrfdwacl, "
8907                                                   "array_to_string(ARRAY("
8908                                                   "SELECT quote_ident(option_name) || ' ' || "
8909                                                   "quote_literal(option_value) "
8910                                                   "FROM pg_options_to_table(f.fdwoptions) "
8911                                                   "ORDER BY option_name"
8912                                                   "), E',\n    ') AS fdwoptions "
8913                                                   "FROM pg_foreign_data_wrapper f "
8914                                                   "LEFT JOIN pg_init_privs pip ON "
8915                                                   "(f.oid = pip.objoid "
8916                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8917                                                   "AND pip.objsubid = 0) ",
8918                                                   username_subquery,
8919                                                   acl_subquery->data,
8920                                                   racl_subquery->data,
8921                                                   initacl_subquery->data,
8922                                                   initracl_subquery->data);
8923
8924                 destroyPQExpBuffer(acl_subquery);
8925                 destroyPQExpBuffer(racl_subquery);
8926                 destroyPQExpBuffer(initacl_subquery);
8927                 destroyPQExpBuffer(initracl_subquery);
8928         }
8929         else if (fout->remoteVersion >= 90100)
8930         {
8931                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8932                                                   "(%s fdwowner) AS rolname, "
8933                                                   "fdwhandler::pg_catalog.regproc, "
8934                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8935                                                   "NULL as rfdwacl, "
8936                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8937                                                   "array_to_string(ARRAY("
8938                                                   "SELECT quote_ident(option_name) || ' ' || "
8939                                                   "quote_literal(option_value) "
8940                                                   "FROM pg_options_to_table(fdwoptions) "
8941                                                   "ORDER BY option_name"
8942                                                   "), E',\n    ') AS fdwoptions "
8943                                                   "FROM pg_foreign_data_wrapper",
8944                                                   username_subquery);
8945         }
8946         else
8947         {
8948                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8949                                                   "(%s fdwowner) AS rolname, "
8950                                                   "'-' AS fdwhandler, "
8951                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8952                                                   "NULL as rfdwacl, "
8953                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8954                                                   "array_to_string(ARRAY("
8955                                                   "SELECT quote_ident(option_name) || ' ' || "
8956                                                   "quote_literal(option_value) "
8957                                                   "FROM pg_options_to_table(fdwoptions) "
8958                                                   "ORDER BY option_name"
8959                                                   "), E',\n    ') AS fdwoptions "
8960                                                   "FROM pg_foreign_data_wrapper",
8961                                                   username_subquery);
8962         }
8963
8964         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8965
8966         ntups = PQntuples(res);
8967         *numForeignDataWrappers = ntups;
8968
8969         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
8970
8971         i_tableoid = PQfnumber(res, "tableoid");
8972         i_oid = PQfnumber(res, "oid");
8973         i_fdwname = PQfnumber(res, "fdwname");
8974         i_rolname = PQfnumber(res, "rolname");
8975         i_fdwhandler = PQfnumber(res, "fdwhandler");
8976         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
8977         i_fdwacl = PQfnumber(res, "fdwacl");
8978         i_rfdwacl = PQfnumber(res, "rfdwacl");
8979         i_initfdwacl = PQfnumber(res, "initfdwacl");
8980         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
8981         i_fdwoptions = PQfnumber(res, "fdwoptions");
8982
8983         for (i = 0; i < ntups; i++)
8984         {
8985                 fdwinfo[i].dobj.objType = DO_FDW;
8986                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8987                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8988                 AssignDumpId(&fdwinfo[i].dobj);
8989                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
8990                 fdwinfo[i].dobj.namespace = NULL;
8991                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8992                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
8993                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
8994                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
8995                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
8996                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
8997                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
8998                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
8999
9000                 /* Decide whether we want to dump it */
9001                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9002
9003                 /* Do not try to dump ACL if no ACL exists. */
9004                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9005                         PQgetisnull(res, i, i_initfdwacl) &&
9006                         PQgetisnull(res, i, i_initrfdwacl))
9007                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9008         }
9009
9010         PQclear(res);
9011
9012         destroyPQExpBuffer(query);
9013
9014         return fdwinfo;
9015 }
9016
9017 /*
9018  * getForeignServers:
9019  *        read all foreign servers in the system catalogs and return
9020  *        them in the ForeignServerInfo * structure
9021  *
9022  *      numForeignServers is set to the number of servers read in
9023  */
9024 ForeignServerInfo *
9025 getForeignServers(Archive *fout, int *numForeignServers)
9026 {
9027         DumpOptions *dopt = fout->dopt;
9028         PGresult   *res;
9029         int                     ntups;
9030         int                     i;
9031         PQExpBuffer query;
9032         ForeignServerInfo *srvinfo;
9033         int                     i_tableoid;
9034         int                     i_oid;
9035         int                     i_srvname;
9036         int                     i_rolname;
9037         int                     i_srvfdw;
9038         int                     i_srvtype;
9039         int                     i_srvversion;
9040         int                     i_srvacl;
9041         int                     i_rsrvacl;
9042         int                     i_initsrvacl;
9043         int                     i_initrsrvacl;
9044         int                     i_srvoptions;
9045
9046         /* Before 8.4, there are no foreign servers */
9047         if (fout->remoteVersion < 80400)
9048         {
9049                 *numForeignServers = 0;
9050                 return NULL;
9051         }
9052
9053         query = createPQExpBuffer();
9054
9055         if (fout->remoteVersion >= 90600)
9056         {
9057                 PQExpBuffer acl_subquery = createPQExpBuffer();
9058                 PQExpBuffer racl_subquery = createPQExpBuffer();
9059                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9060                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9061
9062                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9063                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9064                                                 dopt->binary_upgrade);
9065
9066                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9067                                                   "(%s f.srvowner) AS rolname, "
9068                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9069                                                   "%s AS srvacl, "
9070                                                   "%s AS rsrvacl, "
9071                                                   "%s AS initsrvacl, "
9072                                                   "%s AS initrsrvacl, "
9073                                                   "array_to_string(ARRAY("
9074                                                   "SELECT quote_ident(option_name) || ' ' || "
9075                                                   "quote_literal(option_value) "
9076                                                   "FROM pg_options_to_table(f.srvoptions) "
9077                                                   "ORDER BY option_name"
9078                                                   "), E',\n    ') AS srvoptions "
9079                                                   "FROM pg_foreign_server f "
9080                                                   "LEFT JOIN pg_init_privs pip "
9081                                                   "ON (f.oid = pip.objoid "
9082                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9083                                                   "AND pip.objsubid = 0) ",
9084                                                   username_subquery,
9085                                                   acl_subquery->data,
9086                                                   racl_subquery->data,
9087                                                   initacl_subquery->data,
9088                                                   initracl_subquery->data);
9089
9090                 destroyPQExpBuffer(acl_subquery);
9091                 destroyPQExpBuffer(racl_subquery);
9092                 destroyPQExpBuffer(initacl_subquery);
9093                 destroyPQExpBuffer(initracl_subquery);
9094         }
9095         else
9096         {
9097                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9098                                                   "(%s srvowner) AS rolname, "
9099                                                   "srvfdw, srvtype, srvversion, srvacl, "
9100                                                   "NULL AS rsrvacl, "
9101                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9102                                                   "array_to_string(ARRAY("
9103                                                   "SELECT quote_ident(option_name) || ' ' || "
9104                                                   "quote_literal(option_value) "
9105                                                   "FROM pg_options_to_table(srvoptions) "
9106                                                   "ORDER BY option_name"
9107                                                   "), E',\n    ') AS srvoptions "
9108                                                   "FROM pg_foreign_server",
9109                                                   username_subquery);
9110         }
9111
9112         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9113
9114         ntups = PQntuples(res);
9115         *numForeignServers = ntups;
9116
9117         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9118
9119         i_tableoid = PQfnumber(res, "tableoid");
9120         i_oid = PQfnumber(res, "oid");
9121         i_srvname = PQfnumber(res, "srvname");
9122         i_rolname = PQfnumber(res, "rolname");
9123         i_srvfdw = PQfnumber(res, "srvfdw");
9124         i_srvtype = PQfnumber(res, "srvtype");
9125         i_srvversion = PQfnumber(res, "srvversion");
9126         i_srvacl = PQfnumber(res, "srvacl");
9127         i_rsrvacl = PQfnumber(res, "rsrvacl");
9128         i_initsrvacl = PQfnumber(res, "initsrvacl");
9129         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9130         i_srvoptions = PQfnumber(res, "srvoptions");
9131
9132         for (i = 0; i < ntups; i++)
9133         {
9134                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9135                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9136                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9137                 AssignDumpId(&srvinfo[i].dobj);
9138                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9139                 srvinfo[i].dobj.namespace = NULL;
9140                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9141                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9142                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9143                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9144                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9145                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9146                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9147                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9148                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9149
9150                 /* Decide whether we want to dump it */
9151                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9152
9153                 /* Do not try to dump ACL if no ACL exists. */
9154                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9155                         PQgetisnull(res, i, i_initsrvacl) &&
9156                         PQgetisnull(res, i, i_initrsrvacl))
9157                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9158         }
9159
9160         PQclear(res);
9161
9162         destroyPQExpBuffer(query);
9163
9164         return srvinfo;
9165 }
9166
9167 /*
9168  * getDefaultACLs:
9169  *        read all default ACL information in the system catalogs and return
9170  *        them in the DefaultACLInfo structure
9171  *
9172  *      numDefaultACLs is set to the number of ACLs read in
9173  */
9174 DefaultACLInfo *
9175 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9176 {
9177         DumpOptions *dopt = fout->dopt;
9178         DefaultACLInfo *daclinfo;
9179         PQExpBuffer query;
9180         PGresult   *res;
9181         int                     i_oid;
9182         int                     i_tableoid;
9183         int                     i_defaclrole;
9184         int                     i_defaclnamespace;
9185         int                     i_defaclobjtype;
9186         int                     i_defaclacl;
9187         int                     i_rdefaclacl;
9188         int                     i_initdefaclacl;
9189         int                     i_initrdefaclacl;
9190         int                     i,
9191                                 ntups;
9192
9193         if (fout->remoteVersion < 90000)
9194         {
9195                 *numDefaultACLs = 0;
9196                 return NULL;
9197         }
9198
9199         query = createPQExpBuffer();
9200
9201         if (fout->remoteVersion >= 90600)
9202         {
9203                 PQExpBuffer acl_subquery = createPQExpBuffer();
9204                 PQExpBuffer racl_subquery = createPQExpBuffer();
9205                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9206                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9207
9208                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9209                                                 initracl_subquery, "defaclacl", "defaclrole",
9210                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9211                                                 dopt->binary_upgrade);
9212
9213                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9214                                                   "(%s d.defaclrole) AS defaclrole, "
9215                                                   "d.defaclnamespace, "
9216                                                   "d.defaclobjtype, "
9217                                                   "%s AS defaclacl, "
9218                                                   "%s AS rdefaclacl, "
9219                                                   "%s AS initdefaclacl, "
9220                                                   "%s AS initrdefaclacl "
9221                                                   "FROM pg_default_acl d "
9222                                                   "LEFT JOIN pg_init_privs pip ON "
9223                                                   "(d.oid = pip.objoid "
9224                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9225                                                   "AND pip.objsubid = 0) ",
9226                                                   username_subquery,
9227                                                   acl_subquery->data,
9228                                                   racl_subquery->data,
9229                                                   initacl_subquery->data,
9230                                                   initracl_subquery->data);
9231         }
9232         else
9233         {
9234                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9235                                                   "(%s defaclrole) AS defaclrole, "
9236                                                   "defaclnamespace, "
9237                                                   "defaclobjtype, "
9238                                                   "defaclacl, "
9239                                                   "NULL AS rdefaclacl, "
9240                                                   "NULL AS initdefaclacl, "
9241                                                   "NULL AS initrdefaclacl "
9242                                                   "FROM pg_default_acl",
9243                                                   username_subquery);
9244         }
9245
9246         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9247
9248         ntups = PQntuples(res);
9249         *numDefaultACLs = ntups;
9250
9251         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9252
9253         i_oid = PQfnumber(res, "oid");
9254         i_tableoid = PQfnumber(res, "tableoid");
9255         i_defaclrole = PQfnumber(res, "defaclrole");
9256         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9257         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9258         i_defaclacl = PQfnumber(res, "defaclacl");
9259         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9260         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9261         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9262
9263         for (i = 0; i < ntups; i++)
9264         {
9265                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9266
9267                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9268                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9269                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9270                 AssignDumpId(&daclinfo[i].dobj);
9271                 /* cheesy ... is it worth coming up with a better object name? */
9272                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9273
9274                 if (nspid != InvalidOid)
9275                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9276                 else
9277                         daclinfo[i].dobj.namespace = NULL;
9278
9279                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9280                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9281                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9282                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9283                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9284                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9285
9286                 /* Decide whether we want to dump it */
9287                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9288         }
9289
9290         PQclear(res);
9291
9292         destroyPQExpBuffer(query);
9293
9294         return daclinfo;
9295 }
9296
9297 /*
9298  * dumpComment --
9299  *
9300  * This routine is used to dump any comments associated with the
9301  * object handed to this routine. The routine takes the object type
9302  * and object name (ready to print, except for schema decoration), plus
9303  * the namespace and owner of the object (for labeling the ArchiveEntry),
9304  * plus catalog ID and subid which are the lookup key for pg_description,
9305  * plus the dump ID for the object (for setting a dependency).
9306  * If a matching pg_description entry is found, it is dumped.
9307  *
9308  * Note: in some cases, such as comments for triggers and rules, the "type"
9309  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9310  * but it doesn't seem worth complicating the API for all callers to make
9311  * it cleaner.
9312  *
9313  * Note: although this routine takes a dumpId for dependency purposes,
9314  * that purpose is just to mark the dependency in the emitted dump file
9315  * for possible future use by pg_restore.  We do NOT use it for determining
9316  * ordering of the comment in the dump file, because this routine is called
9317  * after dependency sorting occurs.  This routine should be called just after
9318  * calling ArchiveEntry() for the specified object.
9319  */
9320 static void
9321 dumpComment(Archive *fout, const char *type, const char *name,
9322                         const char *namespace, const char *owner,
9323                         CatalogId catalogId, int subid, DumpId dumpId)
9324 {
9325         DumpOptions *dopt = fout->dopt;
9326         CommentItem *comments;
9327         int                     ncomments;
9328
9329         /* do nothing, if --no-comments is supplied */
9330         if (dopt->no_comments)
9331                 return;
9332
9333         /* Comments are schema not data ... except blob comments are data */
9334         if (strcmp(type, "LARGE OBJECT") != 0)
9335         {
9336                 if (dopt->dataOnly)
9337                         return;
9338         }
9339         else
9340         {
9341                 /* We do dump blob comments in binary-upgrade mode */
9342                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9343                         return;
9344         }
9345
9346         /* Search for comments associated with catalogId, using table */
9347         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9348                                                          &comments);
9349
9350         /* Is there one matching the subid? */
9351         while (ncomments > 0)
9352         {
9353                 if (comments->objsubid == subid)
9354                         break;
9355                 comments++;
9356                 ncomments--;
9357         }
9358
9359         /* If a comment exists, build COMMENT ON statement */
9360         if (ncomments > 0)
9361         {
9362                 PQExpBuffer query = createPQExpBuffer();
9363                 PQExpBuffer tag = createPQExpBuffer();
9364
9365                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9366                 if (namespace && *namespace)
9367                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9368                 appendPQExpBuffer(query, "%s IS ", name);
9369                 appendStringLiteralAH(query, comments->descr, fout);
9370                 appendPQExpBufferStr(query, ";\n");
9371
9372                 appendPQExpBuffer(tag, "%s %s", type, name);
9373
9374                 /*
9375                  * We mark comments as SECTION_NONE because they really belong in the
9376                  * same section as their parent, whether that is pre-data or
9377                  * post-data.
9378                  */
9379                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9380                                          tag->data, namespace, NULL, owner,
9381                                          "COMMENT", SECTION_NONE,
9382                                          query->data, "", NULL,
9383                                          &(dumpId), 1,
9384                                          NULL, NULL);
9385
9386                 destroyPQExpBuffer(query);
9387                 destroyPQExpBuffer(tag);
9388         }
9389 }
9390
9391 /*
9392  * dumpTableComment --
9393  *
9394  * As above, but dump comments for both the specified table (or view)
9395  * and its columns.
9396  */
9397 static void
9398 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9399                                  const char *reltypename)
9400 {
9401         DumpOptions *dopt = fout->dopt;
9402         CommentItem *comments;
9403         int                     ncomments;
9404         PQExpBuffer query;
9405         PQExpBuffer tag;
9406
9407         /* do nothing, if --no-comments is supplied */
9408         if (dopt->no_comments)
9409                 return;
9410
9411         /* Comments are SCHEMA not data */
9412         if (dopt->dataOnly)
9413                 return;
9414
9415         /* Search for comments associated with relation, using table */
9416         ncomments = findComments(fout,
9417                                                          tbinfo->dobj.catId.tableoid,
9418                                                          tbinfo->dobj.catId.oid,
9419                                                          &comments);
9420
9421         /* If comments exist, build COMMENT ON statements */
9422         if (ncomments <= 0)
9423                 return;
9424
9425         query = createPQExpBuffer();
9426         tag = createPQExpBuffer();
9427
9428         while (ncomments > 0)
9429         {
9430                 const char *descr = comments->descr;
9431                 int                     objsubid = comments->objsubid;
9432
9433                 if (objsubid == 0)
9434                 {
9435                         resetPQExpBuffer(tag);
9436                         appendPQExpBuffer(tag, "%s %s", reltypename,
9437                                                           fmtId(tbinfo->dobj.name));
9438
9439                         resetPQExpBuffer(query);
9440                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9441                                                           fmtQualifiedDumpable(tbinfo));
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                                                  "COMMENT", SECTION_NONE,
9450                                                  query->data, "", NULL,
9451                                                  &(tbinfo->dobj.dumpId), 1,
9452                                                  NULL, NULL);
9453                 }
9454                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9455                 {
9456                         resetPQExpBuffer(tag);
9457                         appendPQExpBuffer(tag, "COLUMN %s.",
9458                                                           fmtId(tbinfo->dobj.name));
9459                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9460
9461                         resetPQExpBuffer(query);
9462                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9463                                                           fmtQualifiedDumpable(tbinfo));
9464                         appendPQExpBuffer(query, "%s IS ",
9465                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9466                         appendStringLiteralAH(query, descr, fout);
9467                         appendPQExpBufferStr(query, ";\n");
9468
9469                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9470                                                  tag->data,
9471                                                  tbinfo->dobj.namespace->dobj.name,
9472                                                  NULL, tbinfo->rolname,
9473                                                  "COMMENT", SECTION_NONE,
9474                                                  query->data, "", NULL,
9475                                                  &(tbinfo->dobj.dumpId), 1,
9476                                                  NULL, NULL);
9477                 }
9478
9479                 comments++;
9480                 ncomments--;
9481         }
9482
9483         destroyPQExpBuffer(query);
9484         destroyPQExpBuffer(tag);
9485 }
9486
9487 /*
9488  * findComments --
9489  *
9490  * Find the comment(s), if any, associated with the given object.  All the
9491  * objsubid values associated with the given classoid/objoid are found with
9492  * one search.
9493  */
9494 static int
9495 findComments(Archive *fout, Oid classoid, Oid objoid,
9496                          CommentItem **items)
9497 {
9498         /* static storage for table of comments */
9499         static CommentItem *comments = NULL;
9500         static int      ncomments = -1;
9501
9502         CommentItem *middle = NULL;
9503         CommentItem *low;
9504         CommentItem *high;
9505         int                     nmatch;
9506
9507         /* Get comments if we didn't already */
9508         if (ncomments < 0)
9509                 ncomments = collectComments(fout, &comments);
9510
9511         /*
9512          * Do binary search to find some item matching the object.
9513          */
9514         low = &comments[0];
9515         high = &comments[ncomments - 1];
9516         while (low <= high)
9517         {
9518                 middle = low + (high - low) / 2;
9519
9520                 if (classoid < middle->classoid)
9521                         high = middle - 1;
9522                 else if (classoid > middle->classoid)
9523                         low = middle + 1;
9524                 else if (objoid < middle->objoid)
9525                         high = middle - 1;
9526                 else if (objoid > middle->objoid)
9527                         low = middle + 1;
9528                 else
9529                         break;                          /* found a match */
9530         }
9531
9532         if (low > high)                         /* no matches */
9533         {
9534                 *items = NULL;
9535                 return 0;
9536         }
9537
9538         /*
9539          * Now determine how many items match the object.  The search loop
9540          * invariant still holds: only items between low and high inclusive could
9541          * match.
9542          */
9543         nmatch = 1;
9544         while (middle > low)
9545         {
9546                 if (classoid != middle[-1].classoid ||
9547                         objoid != middle[-1].objoid)
9548                         break;
9549                 middle--;
9550                 nmatch++;
9551         }
9552
9553         *items = middle;
9554
9555         middle += nmatch;
9556         while (middle <= high)
9557         {
9558                 if (classoid != middle->classoid ||
9559                         objoid != middle->objoid)
9560                         break;
9561                 middle++;
9562                 nmatch++;
9563         }
9564
9565         return nmatch;
9566 }
9567
9568 /*
9569  * collectComments --
9570  *
9571  * Construct a table of all comments available for database objects.
9572  * We used to do per-object queries for the comments, but it's much faster
9573  * to pull them all over at once, and on most databases the memory cost
9574  * isn't high.
9575  *
9576  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9577  */
9578 static int
9579 collectComments(Archive *fout, CommentItem **items)
9580 {
9581         PGresult   *res;
9582         PQExpBuffer query;
9583         int                     i_description;
9584         int                     i_classoid;
9585         int                     i_objoid;
9586         int                     i_objsubid;
9587         int                     ntups;
9588         int                     i;
9589         CommentItem *comments;
9590
9591         query = createPQExpBuffer();
9592
9593         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9594                                                  "FROM pg_catalog.pg_description "
9595                                                  "ORDER BY classoid, objoid, objsubid");
9596
9597         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9598
9599         /* Construct lookup table containing OIDs in numeric form */
9600
9601         i_description = PQfnumber(res, "description");
9602         i_classoid = PQfnumber(res, "classoid");
9603         i_objoid = PQfnumber(res, "objoid");
9604         i_objsubid = PQfnumber(res, "objsubid");
9605
9606         ntups = PQntuples(res);
9607
9608         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9609
9610         for (i = 0; i < ntups; i++)
9611         {
9612                 comments[i].descr = PQgetvalue(res, i, i_description);
9613                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9614                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9615                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9616         }
9617
9618         /* Do NOT free the PGresult since we are keeping pointers into it */
9619         destroyPQExpBuffer(query);
9620
9621         *items = comments;
9622         return ntups;
9623 }
9624
9625 /*
9626  * dumpDumpableObject
9627  *
9628  * This routine and its subsidiaries are responsible for creating
9629  * ArchiveEntries (TOC objects) for each object to be dumped.
9630  */
9631 static void
9632 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9633 {
9634         switch (dobj->objType)
9635         {
9636                 case DO_NAMESPACE:
9637                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9638                         break;
9639                 case DO_EXTENSION:
9640                         dumpExtension(fout, (ExtensionInfo *) dobj);
9641                         break;
9642                 case DO_TYPE:
9643                         dumpType(fout, (TypeInfo *) dobj);
9644                         break;
9645                 case DO_SHELL_TYPE:
9646                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9647                         break;
9648                 case DO_FUNC:
9649                         dumpFunc(fout, (FuncInfo *) dobj);
9650                         break;
9651                 case DO_AGG:
9652                         dumpAgg(fout, (AggInfo *) dobj);
9653                         break;
9654                 case DO_OPERATOR:
9655                         dumpOpr(fout, (OprInfo *) dobj);
9656                         break;
9657                 case DO_ACCESS_METHOD:
9658                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9659                         break;
9660                 case DO_OPCLASS:
9661                         dumpOpclass(fout, (OpclassInfo *) dobj);
9662                         break;
9663                 case DO_OPFAMILY:
9664                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9665                         break;
9666                 case DO_COLLATION:
9667                         dumpCollation(fout, (CollInfo *) dobj);
9668                         break;
9669                 case DO_CONVERSION:
9670                         dumpConversion(fout, (ConvInfo *) dobj);
9671                         break;
9672                 case DO_TABLE:
9673                         dumpTable(fout, (TableInfo *) dobj);
9674                         break;
9675                 case DO_ATTRDEF:
9676                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9677                         break;
9678                 case DO_INDEX:
9679                         dumpIndex(fout, (IndxInfo *) dobj);
9680                         break;
9681                 case DO_INDEX_ATTACH:
9682                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9683                         break;
9684                 case DO_STATSEXT:
9685                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9686                         break;
9687                 case DO_REFRESH_MATVIEW:
9688                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9689                         break;
9690                 case DO_RULE:
9691                         dumpRule(fout, (RuleInfo *) dobj);
9692                         break;
9693                 case DO_TRIGGER:
9694                         dumpTrigger(fout, (TriggerInfo *) dobj);
9695                         break;
9696                 case DO_EVENT_TRIGGER:
9697                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9698                         break;
9699                 case DO_CONSTRAINT:
9700                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9701                         break;
9702                 case DO_FK_CONSTRAINT:
9703                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9704                         break;
9705                 case DO_PROCLANG:
9706                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9707                         break;
9708                 case DO_CAST:
9709                         dumpCast(fout, (CastInfo *) dobj);
9710                         break;
9711                 case DO_TRANSFORM:
9712                         dumpTransform(fout, (TransformInfo *) dobj);
9713                         break;
9714                 case DO_SEQUENCE_SET:
9715                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9716                         break;
9717                 case DO_TABLE_DATA:
9718                         dumpTableData(fout, (TableDataInfo *) dobj);
9719                         break;
9720                 case DO_DUMMY_TYPE:
9721                         /* table rowtypes and array types are never dumped separately */
9722                         break;
9723                 case DO_TSPARSER:
9724                         dumpTSParser(fout, (TSParserInfo *) dobj);
9725                         break;
9726                 case DO_TSDICT:
9727                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9728                         break;
9729                 case DO_TSTEMPLATE:
9730                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9731                         break;
9732                 case DO_TSCONFIG:
9733                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9734                         break;
9735                 case DO_FDW:
9736                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9737                         break;
9738                 case DO_FOREIGN_SERVER:
9739                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9740                         break;
9741                 case DO_DEFAULT_ACL:
9742                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9743                         break;
9744                 case DO_BLOB:
9745                         dumpBlob(fout, (BlobInfo *) dobj);
9746                         break;
9747                 case DO_BLOB_DATA:
9748                         if (dobj->dump & DUMP_COMPONENT_DATA)
9749                         {
9750                                 TocEntry   *te;
9751
9752                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9753                                                                   dobj->name, NULL, NULL, "",
9754                                                                   "BLOBS", SECTION_DATA,
9755                                                                   "", "", NULL,
9756                                                                   NULL, 0,
9757                                                                   dumpBlobs, NULL);
9758
9759                                 /*
9760                                  * Set the TocEntry's dataLength in case we are doing a
9761                                  * parallel dump and want to order dump jobs by table size.
9762                                  * (We need some size estimate for every TocEntry with a
9763                                  * DataDumper function.)  We don't currently have any cheap
9764                                  * way to estimate the size of blobs, but it doesn't matter;
9765                                  * let's just set the size to a large value so parallel dumps
9766                                  * will launch this job first.  If there's lots of blobs, we
9767                                  * win, and if there aren't, we don't lose much.  (If you want
9768                                  * to improve on this, really what you should be thinking
9769                                  * about is allowing blob dumping to be parallelized, not just
9770                                  * getting a smarter estimate for the single TOC entry.)
9771                                  */
9772                                 te->dataLength = MaxBlockNumber;
9773                         }
9774                         break;
9775                 case DO_POLICY:
9776                         dumpPolicy(fout, (PolicyInfo *) dobj);
9777                         break;
9778                 case DO_PUBLICATION:
9779                         dumpPublication(fout, (PublicationInfo *) dobj);
9780                         break;
9781                 case DO_PUBLICATION_REL:
9782                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9783                         break;
9784                 case DO_SUBSCRIPTION:
9785                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9786                         break;
9787                 case DO_PRE_DATA_BOUNDARY:
9788                 case DO_POST_DATA_BOUNDARY:
9789                         /* never dumped, nothing to do */
9790                         break;
9791         }
9792 }
9793
9794 /*
9795  * dumpNamespace
9796  *        writes out to fout the queries to recreate a user-defined namespace
9797  */
9798 static void
9799 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9800 {
9801         DumpOptions *dopt = fout->dopt;
9802         PQExpBuffer q;
9803         PQExpBuffer delq;
9804         char       *qnspname;
9805
9806         /* Skip if not to be dumped */
9807         if (!nspinfo->dobj.dump || dopt->dataOnly)
9808                 return;
9809
9810         q = createPQExpBuffer();
9811         delq = createPQExpBuffer();
9812
9813         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9814
9815         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9816
9817         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9818
9819         if (dopt->binary_upgrade)
9820                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9821                                                                                 "SCHEMA", qnspname, NULL);
9822
9823         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9824                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9825                                          nspinfo->dobj.name,
9826                                          NULL, NULL,
9827                                          nspinfo->rolname,
9828                                          "SCHEMA", SECTION_PRE_DATA,
9829                                          q->data, delq->data, NULL,
9830                                          NULL, 0,
9831                                          NULL, NULL);
9832
9833         /* Dump Schema Comments and Security Labels */
9834         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9835                 dumpComment(fout, "SCHEMA", qnspname,
9836                                         NULL, nspinfo->rolname,
9837                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9838
9839         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9840                 dumpSecLabel(fout, "SCHEMA", qnspname,
9841                                          NULL, nspinfo->rolname,
9842                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9843
9844         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9845                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9846                                 qnspname, NULL, NULL,
9847                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9848                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9849
9850         free(qnspname);
9851
9852         destroyPQExpBuffer(q);
9853         destroyPQExpBuffer(delq);
9854 }
9855
9856 /*
9857  * dumpExtension
9858  *        writes out to fout the queries to recreate an extension
9859  */
9860 static void
9861 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9862 {
9863         DumpOptions *dopt = fout->dopt;
9864         PQExpBuffer q;
9865         PQExpBuffer delq;
9866         char       *qextname;
9867
9868         /* Skip if not to be dumped */
9869         if (!extinfo->dobj.dump || dopt->dataOnly)
9870                 return;
9871
9872         q = createPQExpBuffer();
9873         delq = createPQExpBuffer();
9874
9875         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9876
9877         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9878
9879         if (!dopt->binary_upgrade)
9880         {
9881                 /*
9882                  * In a regular dump, we simply create the extension, intentionally
9883                  * not specifying a version, so that the destination installation's
9884                  * default version is used.
9885                  *
9886                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9887                  * types; but there are various scenarios in which it's convenient to
9888                  * manually create the desired extension before restoring, so we
9889                  * prefer to allow it to exist already.
9890                  */
9891                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9892                                                   qextname, fmtId(extinfo->namespace));
9893         }
9894         else
9895         {
9896                 /*
9897                  * In binary-upgrade mode, it's critical to reproduce the state of the
9898                  * database exactly, so our procedure is to create an empty extension,
9899                  * restore all the contained objects normally, and add them to the
9900                  * extension one by one.  This function performs just the first of
9901                  * those steps.  binary_upgrade_extension_member() takes care of
9902                  * adding member objects as they're created.
9903                  */
9904                 int                     i;
9905                 int                     n;
9906
9907                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9908
9909                 /*
9910                  * We unconditionally create the extension, so we must drop it if it
9911                  * exists.  This could happen if the user deleted 'plpgsql' and then
9912                  * readded it, causing its oid to be greater than g_last_builtin_oid.
9913                  */
9914                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9915
9916                 appendPQExpBufferStr(q,
9917                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9918                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
9919                 appendPQExpBufferStr(q, ", ");
9920                 appendStringLiteralAH(q, extinfo->namespace, fout);
9921                 appendPQExpBufferStr(q, ", ");
9922                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9923                 appendStringLiteralAH(q, extinfo->extversion, fout);
9924                 appendPQExpBufferStr(q, ", ");
9925
9926                 /*
9927                  * Note that we're pushing extconfig (an OID array) back into
9928                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
9929                  * preserved in binary upgrade.
9930                  */
9931                 if (strlen(extinfo->extconfig) > 2)
9932                         appendStringLiteralAH(q, extinfo->extconfig, fout);
9933                 else
9934                         appendPQExpBufferStr(q, "NULL");
9935                 appendPQExpBufferStr(q, ", ");
9936                 if (strlen(extinfo->extcondition) > 2)
9937                         appendStringLiteralAH(q, extinfo->extcondition, fout);
9938                 else
9939                         appendPQExpBufferStr(q, "NULL");
9940                 appendPQExpBufferStr(q, ", ");
9941                 appendPQExpBufferStr(q, "ARRAY[");
9942                 n = 0;
9943                 for (i = 0; i < extinfo->dobj.nDeps; i++)
9944                 {
9945                         DumpableObject *extobj;
9946
9947                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9948                         if (extobj && extobj->objType == DO_EXTENSION)
9949                         {
9950                                 if (n++ > 0)
9951                                         appendPQExpBufferChar(q, ',');
9952                                 appendStringLiteralAH(q, extobj->name, fout);
9953                         }
9954                 }
9955                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9956                 appendPQExpBufferStr(q, ");\n");
9957         }
9958
9959         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9960                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9961                                          extinfo->dobj.name,
9962                                          NULL, NULL,
9963                                          "",
9964                                          "EXTENSION", SECTION_PRE_DATA,
9965                                          q->data, delq->data, NULL,
9966                                          NULL, 0,
9967                                          NULL, NULL);
9968
9969         /* Dump Extension Comments and Security Labels */
9970         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9971                 dumpComment(fout, "EXTENSION", qextname,
9972                                         NULL, "",
9973                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9974
9975         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9976                 dumpSecLabel(fout, "EXTENSION", qextname,
9977                                          NULL, "",
9978                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9979
9980         free(qextname);
9981
9982         destroyPQExpBuffer(q);
9983         destroyPQExpBuffer(delq);
9984 }
9985
9986 /*
9987  * dumpType
9988  *        writes out to fout the queries to recreate a user-defined type
9989  */
9990 static void
9991 dumpType(Archive *fout, TypeInfo *tyinfo)
9992 {
9993         DumpOptions *dopt = fout->dopt;
9994
9995         /* Skip if not to be dumped */
9996         if (!tyinfo->dobj.dump || dopt->dataOnly)
9997                 return;
9998
9999         /* Dump out in proper style */
10000         if (tyinfo->typtype == TYPTYPE_BASE)
10001                 dumpBaseType(fout, tyinfo);
10002         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10003                 dumpDomain(fout, tyinfo);
10004         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10005                 dumpCompositeType(fout, tyinfo);
10006         else if (tyinfo->typtype == TYPTYPE_ENUM)
10007                 dumpEnumType(fout, tyinfo);
10008         else if (tyinfo->typtype == TYPTYPE_RANGE)
10009                 dumpRangeType(fout, tyinfo);
10010         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10011                 dumpUndefinedType(fout, tyinfo);
10012         else
10013                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
10014                                   tyinfo->dobj.name);
10015 }
10016
10017 /*
10018  * dumpEnumType
10019  *        writes out to fout the queries to recreate a user-defined enum type
10020  */
10021 static void
10022 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10023 {
10024         DumpOptions *dopt = fout->dopt;
10025         PQExpBuffer q = createPQExpBuffer();
10026         PQExpBuffer delq = createPQExpBuffer();
10027         PQExpBuffer query = createPQExpBuffer();
10028         PGresult   *res;
10029         int                     num,
10030                                 i;
10031         Oid                     enum_oid;
10032         char       *qtypname;
10033         char       *qualtypname;
10034         char       *label;
10035
10036         if (fout->remoteVersion >= 90100)
10037                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10038                                                   "FROM pg_catalog.pg_enum "
10039                                                   "WHERE enumtypid = '%u'"
10040                                                   "ORDER BY enumsortorder",
10041                                                   tyinfo->dobj.catId.oid);
10042         else
10043                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10044                                                   "FROM pg_catalog.pg_enum "
10045                                                   "WHERE enumtypid = '%u'"
10046                                                   "ORDER BY oid",
10047                                                   tyinfo->dobj.catId.oid);
10048
10049         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10050
10051         num = PQntuples(res);
10052
10053         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10054         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10055
10056         /*
10057          * CASCADE shouldn't be required here as for normal types since the I/O
10058          * functions are generic and do not get dropped.
10059          */
10060         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10061
10062         if (dopt->binary_upgrade)
10063                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10064                                                                                                  tyinfo->dobj.catId.oid,
10065                                                                                                  false);
10066
10067         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10068                                           qualtypname);
10069
10070         if (!dopt->binary_upgrade)
10071         {
10072                 /* Labels with server-assigned oids */
10073                 for (i = 0; i < num; i++)
10074                 {
10075                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10076                         if (i > 0)
10077                                 appendPQExpBufferChar(q, ',');
10078                         appendPQExpBufferStr(q, "\n    ");
10079                         appendStringLiteralAH(q, label, fout);
10080                 }
10081         }
10082
10083         appendPQExpBufferStr(q, "\n);\n");
10084
10085         if (dopt->binary_upgrade)
10086         {
10087                 /* Labels with dump-assigned (preserved) oids */
10088                 for (i = 0; i < num; i++)
10089                 {
10090                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10091                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10092
10093                         if (i == 0)
10094                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10095                         appendPQExpBuffer(q,
10096                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10097                                                           enum_oid);
10098                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10099                         appendStringLiteralAH(q, label, fout);
10100                         appendPQExpBufferStr(q, ";\n\n");
10101                 }
10102         }
10103
10104         if (dopt->binary_upgrade)
10105                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10106                                                                                 "TYPE", qtypname,
10107                                                                                 tyinfo->dobj.namespace->dobj.name);
10108
10109         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10110                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10111                                          tyinfo->dobj.name,
10112                                          tyinfo->dobj.namespace->dobj.name,
10113                                          NULL,
10114                                          tyinfo->rolname,
10115                                          "TYPE", SECTION_PRE_DATA,
10116                                          q->data, delq->data, NULL,
10117                                          NULL, 0,
10118                                          NULL, NULL);
10119
10120         /* Dump Type Comments and Security Labels */
10121         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10122                 dumpComment(fout, "TYPE", qtypname,
10123                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10124                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10125
10126         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10127                 dumpSecLabel(fout, "TYPE", qtypname,
10128                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10129                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10130
10131         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10132                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10133                                 qtypname, NULL,
10134                                 tyinfo->dobj.namespace->dobj.name,
10135                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10136                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10137
10138         PQclear(res);
10139         destroyPQExpBuffer(q);
10140         destroyPQExpBuffer(delq);
10141         destroyPQExpBuffer(query);
10142         free(qtypname);
10143         free(qualtypname);
10144 }
10145
10146 /*
10147  * dumpRangeType
10148  *        writes out to fout the queries to recreate a user-defined range type
10149  */
10150 static void
10151 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10152 {
10153         DumpOptions *dopt = fout->dopt;
10154         PQExpBuffer q = createPQExpBuffer();
10155         PQExpBuffer delq = createPQExpBuffer();
10156         PQExpBuffer query = createPQExpBuffer();
10157         PGresult   *res;
10158         Oid                     collationOid;
10159         char       *qtypname;
10160         char       *qualtypname;
10161         char       *procname;
10162
10163         appendPQExpBuffer(query,
10164                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10165                                           "opc.opcname AS opcname, "
10166                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10167                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10168                                           "opc.opcdefault, "
10169                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10170                                           "     ELSE rngcollation END AS collation, "
10171                                           "rngcanonical, rngsubdiff "
10172                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10173                                           "     pg_catalog.pg_opclass opc "
10174                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10175                                           "rngtypid = '%u'",
10176                                           tyinfo->dobj.catId.oid);
10177
10178         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10179
10180         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10181         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10182
10183         /*
10184          * CASCADE shouldn't be required here as for normal types since the I/O
10185          * functions are generic and do not get dropped.
10186          */
10187         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10188
10189         if (dopt->binary_upgrade)
10190                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10191                                                                                                  tyinfo->dobj.catId.oid,
10192                                                                                                  false);
10193
10194         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10195                                           qualtypname);
10196
10197         appendPQExpBuffer(q, "\n    subtype = %s",
10198                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10199
10200         /* print subtype_opclass only if not default for subtype */
10201         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10202         {
10203                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10204                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10205
10206                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10207                                                   fmtId(nspname));
10208                 appendPQExpBufferStr(q, fmtId(opcname));
10209         }
10210
10211         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10212         if (OidIsValid(collationOid))
10213         {
10214                 CollInfo   *coll = findCollationByOid(collationOid);
10215
10216                 if (coll)
10217                         appendPQExpBuffer(q, ",\n    collation = %s",
10218                                                           fmtQualifiedDumpable(coll));
10219         }
10220
10221         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10222         if (strcmp(procname, "-") != 0)
10223                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10224
10225         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10226         if (strcmp(procname, "-") != 0)
10227                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10228
10229         appendPQExpBufferStr(q, "\n);\n");
10230
10231         if (dopt->binary_upgrade)
10232                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10233                                                                                 "TYPE", qtypname,
10234                                                                                 tyinfo->dobj.namespace->dobj.name);
10235
10236         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10237                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10238                                          tyinfo->dobj.name,
10239                                          tyinfo->dobj.namespace->dobj.name,
10240                                          NULL,
10241                                          tyinfo->rolname,
10242                                          "TYPE", SECTION_PRE_DATA,
10243                                          q->data, delq->data, NULL,
10244                                          NULL, 0,
10245                                          NULL, NULL);
10246
10247         /* Dump Type Comments and Security Labels */
10248         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10249                 dumpComment(fout, "TYPE", qtypname,
10250                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10251                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10252
10253         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10254                 dumpSecLabel(fout, "TYPE", qtypname,
10255                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10256                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10257
10258         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10259                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10260                                 qtypname, NULL,
10261                                 tyinfo->dobj.namespace->dobj.name,
10262                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10263                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10264
10265         PQclear(res);
10266         destroyPQExpBuffer(q);
10267         destroyPQExpBuffer(delq);
10268         destroyPQExpBuffer(query);
10269         free(qtypname);
10270         free(qualtypname);
10271 }
10272
10273 /*
10274  * dumpUndefinedType
10275  *        writes out to fout the queries to recreate a !typisdefined type
10276  *
10277  * This is a shell type, but we use different terminology to distinguish
10278  * this case from where we have to emit a shell type definition to break
10279  * circular dependencies.  An undefined type shouldn't ever have anything
10280  * depending on it.
10281  */
10282 static void
10283 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10284 {
10285         DumpOptions *dopt = fout->dopt;
10286         PQExpBuffer q = createPQExpBuffer();
10287         PQExpBuffer delq = createPQExpBuffer();
10288         char       *qtypname;
10289         char       *qualtypname;
10290
10291         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10292         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10293
10294         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10295
10296         if (dopt->binary_upgrade)
10297                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10298                                                                                                  tyinfo->dobj.catId.oid,
10299                                                                                                  false);
10300
10301         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10302                                           qualtypname);
10303
10304         if (dopt->binary_upgrade)
10305                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10306                                                                                 "TYPE", qtypname,
10307                                                                                 tyinfo->dobj.namespace->dobj.name);
10308
10309         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10310                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10311                                          tyinfo->dobj.name,
10312                                          tyinfo->dobj.namespace->dobj.name,
10313                                          NULL,
10314                                          tyinfo->rolname,
10315                                          "TYPE", SECTION_PRE_DATA,
10316                                          q->data, delq->data, NULL,
10317                                          NULL, 0,
10318                                          NULL, NULL);
10319
10320         /* Dump Type Comments and Security Labels */
10321         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10322                 dumpComment(fout, "TYPE", qtypname,
10323                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10324                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10325
10326         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10327                 dumpSecLabel(fout, "TYPE", qtypname,
10328                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10329                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10330
10331         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10332                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10333                                 qtypname, NULL,
10334                                 tyinfo->dobj.namespace->dobj.name,
10335                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10336                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10337
10338         destroyPQExpBuffer(q);
10339         destroyPQExpBuffer(delq);
10340         free(qtypname);
10341         free(qualtypname);
10342 }
10343
10344 /*
10345  * dumpBaseType
10346  *        writes out to fout the queries to recreate a user-defined base type
10347  */
10348 static void
10349 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10350 {
10351         DumpOptions *dopt = fout->dopt;
10352         PQExpBuffer q = createPQExpBuffer();
10353         PQExpBuffer delq = createPQExpBuffer();
10354         PQExpBuffer query = createPQExpBuffer();
10355         PGresult   *res;
10356         char       *qtypname;
10357         char       *qualtypname;
10358         char       *typlen;
10359         char       *typinput;
10360         char       *typoutput;
10361         char       *typreceive;
10362         char       *typsend;
10363         char       *typmodin;
10364         char       *typmodout;
10365         char       *typanalyze;
10366         Oid                     typreceiveoid;
10367         Oid                     typsendoid;
10368         Oid                     typmodinoid;
10369         Oid                     typmodoutoid;
10370         Oid                     typanalyzeoid;
10371         char       *typcategory;
10372         char       *typispreferred;
10373         char       *typdelim;
10374         char       *typbyval;
10375         char       *typalign;
10376         char       *typstorage;
10377         char       *typcollatable;
10378         char       *typdefault;
10379         bool            typdefault_is_literal = false;
10380
10381         /* Fetch type-specific details */
10382         if (fout->remoteVersion >= 90100)
10383         {
10384                 appendPQExpBuffer(query, "SELECT typlen, "
10385                                                   "typinput, typoutput, typreceive, typsend, "
10386                                                   "typmodin, typmodout, typanalyze, "
10387                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10388                                                   "typsend::pg_catalog.oid AS typsendoid, "
10389                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10390                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10391                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10392                                                   "typcategory, typispreferred, "
10393                                                   "typdelim, typbyval, typalign, typstorage, "
10394                                                   "(typcollation <> 0) AS typcollatable, "
10395                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10396                                                   "FROM pg_catalog.pg_type "
10397                                                   "WHERE oid = '%u'::pg_catalog.oid",
10398                                                   tyinfo->dobj.catId.oid);
10399         }
10400         else if (fout->remoteVersion >= 80400)
10401         {
10402                 appendPQExpBuffer(query, "SELECT typlen, "
10403                                                   "typinput, typoutput, typreceive, typsend, "
10404                                                   "typmodin, typmodout, typanalyze, "
10405                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10406                                                   "typsend::pg_catalog.oid AS typsendoid, "
10407                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10408                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10409                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10410                                                   "typcategory, typispreferred, "
10411                                                   "typdelim, typbyval, typalign, typstorage, "
10412                                                   "false AS typcollatable, "
10413                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10414                                                   "FROM pg_catalog.pg_type "
10415                                                   "WHERE oid = '%u'::pg_catalog.oid",
10416                                                   tyinfo->dobj.catId.oid);
10417         }
10418         else if (fout->remoteVersion >= 80300)
10419         {
10420                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10421                 appendPQExpBuffer(query, "SELECT typlen, "
10422                                                   "typinput, typoutput, typreceive, typsend, "
10423                                                   "typmodin, typmodout, typanalyze, "
10424                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10425                                                   "typsend::pg_catalog.oid AS typsendoid, "
10426                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10427                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10428                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10429                                                   "'U' AS typcategory, false AS typispreferred, "
10430                                                   "typdelim, typbyval, typalign, typstorage, "
10431                                                   "false AS typcollatable, "
10432                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10433                                                   "FROM pg_catalog.pg_type "
10434                                                   "WHERE oid = '%u'::pg_catalog.oid",
10435                                                   tyinfo->dobj.catId.oid);
10436         }
10437         else
10438         {
10439                 appendPQExpBuffer(query, "SELECT typlen, "
10440                                                   "typinput, typoutput, typreceive, typsend, "
10441                                                   "'-' AS typmodin, '-' AS typmodout, "
10442                                                   "typanalyze, "
10443                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10444                                                   "typsend::pg_catalog.oid AS typsendoid, "
10445                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10446                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10447                                                   "'U' AS typcategory, false AS typispreferred, "
10448                                                   "typdelim, typbyval, typalign, typstorage, "
10449                                                   "false AS typcollatable, "
10450                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10451                                                   "FROM pg_catalog.pg_type "
10452                                                   "WHERE oid = '%u'::pg_catalog.oid",
10453                                                   tyinfo->dobj.catId.oid);
10454         }
10455
10456         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10457
10458         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10459         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10460         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10461         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10462         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10463         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10464         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10465         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10466         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10467         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10468         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10469         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10470         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10471         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10472         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10473         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10474         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10475         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10476         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10477         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10478         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10479                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10480         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10481         {
10482                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10483                 typdefault_is_literal = true;   /* it needs quotes */
10484         }
10485         else
10486                 typdefault = NULL;
10487
10488         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10489         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10490
10491         /*
10492          * The reason we include CASCADE is that the circular dependency between
10493          * the type and its I/O functions makes it impossible to drop the type any
10494          * other way.
10495          */
10496         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10497
10498         /*
10499          * We might already have a shell type, but setting pg_type_oid is
10500          * harmless, and in any case we'd better set the array type OID.
10501          */
10502         if (dopt->binary_upgrade)
10503                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10504                                                                                                  tyinfo->dobj.catId.oid,
10505                                                                                                  false);
10506
10507         appendPQExpBuffer(q,
10508                                           "CREATE TYPE %s (\n"
10509                                           "    INTERNALLENGTH = %s",
10510                                           qualtypname,
10511                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10512
10513         /* regproc result is sufficiently quoted already */
10514         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10515         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10516         if (OidIsValid(typreceiveoid))
10517                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10518         if (OidIsValid(typsendoid))
10519                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10520         if (OidIsValid(typmodinoid))
10521                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10522         if (OidIsValid(typmodoutoid))
10523                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10524         if (OidIsValid(typanalyzeoid))
10525                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10526
10527         if (strcmp(typcollatable, "t") == 0)
10528                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10529
10530         if (typdefault != NULL)
10531         {
10532                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10533                 if (typdefault_is_literal)
10534                         appendStringLiteralAH(q, typdefault, fout);
10535                 else
10536                         appendPQExpBufferStr(q, typdefault);
10537         }
10538
10539         if (OidIsValid(tyinfo->typelem))
10540         {
10541                 char       *elemType;
10542
10543                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10544                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10545                 free(elemType);
10546         }
10547
10548         if (strcmp(typcategory, "U") != 0)
10549         {
10550                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10551                 appendStringLiteralAH(q, typcategory, fout);
10552         }
10553
10554         if (strcmp(typispreferred, "t") == 0)
10555                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10556
10557         if (typdelim && strcmp(typdelim, ",") != 0)
10558         {
10559                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10560                 appendStringLiteralAH(q, typdelim, fout);
10561         }
10562
10563         if (strcmp(typalign, "c") == 0)
10564                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10565         else if (strcmp(typalign, "s") == 0)
10566                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10567         else if (strcmp(typalign, "i") == 0)
10568                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10569         else if (strcmp(typalign, "d") == 0)
10570                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10571
10572         if (strcmp(typstorage, "p") == 0)
10573                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10574         else if (strcmp(typstorage, "e") == 0)
10575                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10576         else if (strcmp(typstorage, "x") == 0)
10577                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10578         else if (strcmp(typstorage, "m") == 0)
10579                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10580
10581         if (strcmp(typbyval, "t") == 0)
10582                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10583
10584         appendPQExpBufferStr(q, "\n);\n");
10585
10586         if (dopt->binary_upgrade)
10587                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10588                                                                                 "TYPE", qtypname,
10589                                                                                 tyinfo->dobj.namespace->dobj.name);
10590
10591         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10592                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10593                                          tyinfo->dobj.name,
10594                                          tyinfo->dobj.namespace->dobj.name,
10595                                          NULL,
10596                                          tyinfo->rolname,
10597                                          "TYPE", SECTION_PRE_DATA,
10598                                          q->data, delq->data, NULL,
10599                                          NULL, 0,
10600                                          NULL, NULL);
10601
10602         /* Dump Type Comments and Security Labels */
10603         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10604                 dumpComment(fout, "TYPE", qtypname,
10605                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10606                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10607
10608         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10609                 dumpSecLabel(fout, "TYPE", qtypname,
10610                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10611                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10612
10613         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10614                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10615                                 qtypname, NULL,
10616                                 tyinfo->dobj.namespace->dobj.name,
10617                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10618                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10619
10620         PQclear(res);
10621         destroyPQExpBuffer(q);
10622         destroyPQExpBuffer(delq);
10623         destroyPQExpBuffer(query);
10624         free(qtypname);
10625         free(qualtypname);
10626 }
10627
10628 /*
10629  * dumpDomain
10630  *        writes out to fout the queries to recreate a user-defined domain
10631  */
10632 static void
10633 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10634 {
10635         DumpOptions *dopt = fout->dopt;
10636         PQExpBuffer q = createPQExpBuffer();
10637         PQExpBuffer delq = createPQExpBuffer();
10638         PQExpBuffer query = createPQExpBuffer();
10639         PGresult   *res;
10640         int                     i;
10641         char       *qtypname;
10642         char       *qualtypname;
10643         char       *typnotnull;
10644         char       *typdefn;
10645         char       *typdefault;
10646         Oid                     typcollation;
10647         bool            typdefault_is_literal = false;
10648
10649         /* Fetch domain specific details */
10650         if (fout->remoteVersion >= 90100)
10651         {
10652                 /* typcollation is new in 9.1 */
10653                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10654                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10655                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10656                                                   "t.typdefault, "
10657                                                   "CASE WHEN t.typcollation <> u.typcollation "
10658                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10659                                                   "FROM pg_catalog.pg_type t "
10660                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10661                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10662                                                   tyinfo->dobj.catId.oid);
10663         }
10664         else
10665         {
10666                 appendPQExpBuffer(query, "SELECT typnotnull, "
10667                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10668                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10669                                                   "typdefault, 0 AS typcollation "
10670                                                   "FROM pg_catalog.pg_type "
10671                                                   "WHERE oid = '%u'::pg_catalog.oid",
10672                                                   tyinfo->dobj.catId.oid);
10673         }
10674
10675         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10676
10677         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10678         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10679         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10680                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10681         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10682         {
10683                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10684                 typdefault_is_literal = true;   /* it needs quotes */
10685         }
10686         else
10687                 typdefault = NULL;
10688         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10689
10690         if (dopt->binary_upgrade)
10691                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10692                                                                                                  tyinfo->dobj.catId.oid,
10693                                                                                                  true); /* force array type */
10694
10695         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10696         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10697
10698         appendPQExpBuffer(q,
10699                                           "CREATE DOMAIN %s AS %s",
10700                                           qualtypname,
10701                                           typdefn);
10702
10703         /* Print collation only if different from base type's collation */
10704         if (OidIsValid(typcollation))
10705         {
10706                 CollInfo   *coll;
10707
10708                 coll = findCollationByOid(typcollation);
10709                 if (coll)
10710                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10711         }
10712
10713         if (typnotnull[0] == 't')
10714                 appendPQExpBufferStr(q, " NOT NULL");
10715
10716         if (typdefault != NULL)
10717         {
10718                 appendPQExpBufferStr(q, " DEFAULT ");
10719                 if (typdefault_is_literal)
10720                         appendStringLiteralAH(q, typdefault, fout);
10721                 else
10722                         appendPQExpBufferStr(q, typdefault);
10723         }
10724
10725         PQclear(res);
10726
10727         /*
10728          * Add any CHECK constraints for the domain
10729          */
10730         for (i = 0; i < tyinfo->nDomChecks; i++)
10731         {
10732                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10733
10734                 if (!domcheck->separate)
10735                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10736                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10737         }
10738
10739         appendPQExpBufferStr(q, ";\n");
10740
10741         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10742
10743         if (dopt->binary_upgrade)
10744                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10745                                                                                 "DOMAIN", qtypname,
10746                                                                                 tyinfo->dobj.namespace->dobj.name);
10747
10748         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10749                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10750                                          tyinfo->dobj.name,
10751                                          tyinfo->dobj.namespace->dobj.name,
10752                                          NULL,
10753                                          tyinfo->rolname,
10754                                          "DOMAIN", SECTION_PRE_DATA,
10755                                          q->data, delq->data, NULL,
10756                                          NULL, 0,
10757                                          NULL, NULL);
10758
10759         /* Dump Domain Comments and Security Labels */
10760         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10761                 dumpComment(fout, "DOMAIN", qtypname,
10762                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10763                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10764
10765         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10766                 dumpSecLabel(fout, "DOMAIN", qtypname,
10767                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10768                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10769
10770         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10771                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10772                                 qtypname, NULL,
10773                                 tyinfo->dobj.namespace->dobj.name,
10774                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10775                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10776
10777         /* Dump any per-constraint comments */
10778         for (i = 0; i < tyinfo->nDomChecks; i++)
10779         {
10780                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10781                 PQExpBuffer conprefix = createPQExpBuffer();
10782
10783                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10784                                                   fmtId(domcheck->dobj.name));
10785
10786                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10787                         dumpComment(fout, conprefix->data, qtypname,
10788                                                 tyinfo->dobj.namespace->dobj.name,
10789                                                 tyinfo->rolname,
10790                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10791
10792                 destroyPQExpBuffer(conprefix);
10793         }
10794
10795         destroyPQExpBuffer(q);
10796         destroyPQExpBuffer(delq);
10797         destroyPQExpBuffer(query);
10798         free(qtypname);
10799         free(qualtypname);
10800 }
10801
10802 /*
10803  * dumpCompositeType
10804  *        writes out to fout the queries to recreate a user-defined stand-alone
10805  *        composite type
10806  */
10807 static void
10808 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10809 {
10810         DumpOptions *dopt = fout->dopt;
10811         PQExpBuffer q = createPQExpBuffer();
10812         PQExpBuffer dropped = createPQExpBuffer();
10813         PQExpBuffer delq = createPQExpBuffer();
10814         PQExpBuffer query = createPQExpBuffer();
10815         PGresult   *res;
10816         char       *qtypname;
10817         char       *qualtypname;
10818         int                     ntups;
10819         int                     i_attname;
10820         int                     i_atttypdefn;
10821         int                     i_attlen;
10822         int                     i_attalign;
10823         int                     i_attisdropped;
10824         int                     i_attcollation;
10825         int                     i;
10826         int                     actual_atts;
10827
10828         /* Fetch type specific details */
10829         if (fout->remoteVersion >= 90100)
10830         {
10831                 /*
10832                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10833                  * clauses for attributes whose collation is different from their
10834                  * type's default, we use a CASE here to suppress uninteresting
10835                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10836                  * collation does not matter for those.
10837                  */
10838                 appendPQExpBuffer(query, "SELECT a.attname, "
10839                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10840                                                   "a.attlen, a.attalign, a.attisdropped, "
10841                                                   "CASE WHEN a.attcollation <> at.typcollation "
10842                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10843                                                   "FROM pg_catalog.pg_type ct "
10844                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10845                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10846                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10847                                                   "ORDER BY a.attnum ",
10848                                                   tyinfo->dobj.catId.oid);
10849         }
10850         else
10851         {
10852                 /*
10853                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10854                  * should always be false.
10855                  */
10856                 appendPQExpBuffer(query, "SELECT a.attname, "
10857                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10858                                                   "a.attlen, a.attalign, a.attisdropped, "
10859                                                   "0 AS attcollation "
10860                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10861                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10862                                                   "AND a.attrelid = ct.typrelid "
10863                                                   "ORDER BY a.attnum ",
10864                                                   tyinfo->dobj.catId.oid);
10865         }
10866
10867         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10868
10869         ntups = PQntuples(res);
10870
10871         i_attname = PQfnumber(res, "attname");
10872         i_atttypdefn = PQfnumber(res, "atttypdefn");
10873         i_attlen = PQfnumber(res, "attlen");
10874         i_attalign = PQfnumber(res, "attalign");
10875         i_attisdropped = PQfnumber(res, "attisdropped");
10876         i_attcollation = PQfnumber(res, "attcollation");
10877
10878         if (dopt->binary_upgrade)
10879         {
10880                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10881                                                                                                  tyinfo->dobj.catId.oid,
10882                                                                                                  false);
10883                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10884         }
10885
10886         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10887         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10888
10889         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10890                                           qualtypname);
10891
10892         actual_atts = 0;
10893         for (i = 0; i < ntups; i++)
10894         {
10895                 char       *attname;
10896                 char       *atttypdefn;
10897                 char       *attlen;
10898                 char       *attalign;
10899                 bool            attisdropped;
10900                 Oid                     attcollation;
10901
10902                 attname = PQgetvalue(res, i, i_attname);
10903                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10904                 attlen = PQgetvalue(res, i, i_attlen);
10905                 attalign = PQgetvalue(res, i, i_attalign);
10906                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10907                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10908
10909                 if (attisdropped && !dopt->binary_upgrade)
10910                         continue;
10911
10912                 /* Format properly if not first attr */
10913                 if (actual_atts++ > 0)
10914                         appendPQExpBufferChar(q, ',');
10915                 appendPQExpBufferStr(q, "\n\t");
10916
10917                 if (!attisdropped)
10918                 {
10919                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10920
10921                         /* Add collation if not default for the column type */
10922                         if (OidIsValid(attcollation))
10923                         {
10924                                 CollInfo   *coll;
10925
10926                                 coll = findCollationByOid(attcollation);
10927                                 if (coll)
10928                                         appendPQExpBuffer(q, " COLLATE %s",
10929                                                                           fmtQualifiedDumpable(coll));
10930                         }
10931                 }
10932                 else
10933                 {
10934                         /*
10935                          * This is a dropped attribute and we're in binary_upgrade mode.
10936                          * Insert a placeholder for it in the CREATE TYPE command, and set
10937                          * length and alignment with direct UPDATE to the catalogs
10938                          * afterwards. See similar code in dumpTableSchema().
10939                          */
10940                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10941
10942                         /* stash separately for insertion after the CREATE TYPE */
10943                         appendPQExpBufferStr(dropped,
10944                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
10945                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10946                                                           "SET attlen = %s, "
10947                                                           "attalign = '%s', attbyval = false\n"
10948                                                           "WHERE attname = ", attlen, attalign);
10949                         appendStringLiteralAH(dropped, attname, fout);
10950                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
10951                         appendStringLiteralAH(dropped, qualtypname, fout);
10952                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10953
10954                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10955                                                           qualtypname);
10956                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10957                                                           fmtId(attname));
10958                 }
10959         }
10960         appendPQExpBufferStr(q, "\n);\n");
10961         appendPQExpBufferStr(q, dropped->data);
10962
10963         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10964
10965         if (dopt->binary_upgrade)
10966                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10967                                                                                 "TYPE", qtypname,
10968                                                                                 tyinfo->dobj.namespace->dobj.name);
10969
10970         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10971                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10972                                          tyinfo->dobj.name,
10973                                          tyinfo->dobj.namespace->dobj.name,
10974                                          NULL,
10975                                          tyinfo->rolname,
10976                                          "TYPE", SECTION_PRE_DATA,
10977                                          q->data, delq->data, NULL,
10978                                          NULL, 0,
10979                                          NULL, NULL);
10980
10981
10982         /* Dump Type Comments and Security Labels */
10983         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10984                 dumpComment(fout, "TYPE", qtypname,
10985                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10986                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10987
10988         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10989                 dumpSecLabel(fout, "TYPE", qtypname,
10990                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10991                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10992
10993         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10994                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10995                                 qtypname, NULL,
10996                                 tyinfo->dobj.namespace->dobj.name,
10997                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10998                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10999
11000         PQclear(res);
11001         destroyPQExpBuffer(q);
11002         destroyPQExpBuffer(dropped);
11003         destroyPQExpBuffer(delq);
11004         destroyPQExpBuffer(query);
11005         free(qtypname);
11006         free(qualtypname);
11007
11008         /* Dump any per-column comments */
11009         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11010                 dumpCompositeTypeColComments(fout, tyinfo);
11011 }
11012
11013 /*
11014  * dumpCompositeTypeColComments
11015  *        writes out to fout the queries to recreate comments on the columns of
11016  *        a user-defined stand-alone composite type
11017  */
11018 static void
11019 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11020 {
11021         CommentItem *comments;
11022         int                     ncomments;
11023         PGresult   *res;
11024         PQExpBuffer query;
11025         PQExpBuffer target;
11026         Oid                     pgClassOid;
11027         int                     i;
11028         int                     ntups;
11029         int                     i_attname;
11030         int                     i_attnum;
11031
11032         /* do nothing, if --no-comments is supplied */
11033         if (fout->dopt->no_comments)
11034                 return;
11035
11036         query = createPQExpBuffer();
11037
11038         appendPQExpBuffer(query,
11039                                           "SELECT c.tableoid, a.attname, a.attnum "
11040                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11041                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11042                                           "  AND NOT a.attisdropped "
11043                                           "ORDER BY a.attnum ",
11044                                           tyinfo->typrelid);
11045
11046         /* Fetch column attnames */
11047         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11048
11049         ntups = PQntuples(res);
11050         if (ntups < 1)
11051         {
11052                 PQclear(res);
11053                 destroyPQExpBuffer(query);
11054                 return;
11055         }
11056
11057         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11058
11059         /* Search for comments associated with type's pg_class OID */
11060         ncomments = findComments(fout,
11061                                                          pgClassOid,
11062                                                          tyinfo->typrelid,
11063                                                          &comments);
11064
11065         /* If no comments exist, we're done */
11066         if (ncomments <= 0)
11067         {
11068                 PQclear(res);
11069                 destroyPQExpBuffer(query);
11070                 return;
11071         }
11072
11073         /* Build COMMENT ON statements */
11074         target = createPQExpBuffer();
11075
11076         i_attnum = PQfnumber(res, "attnum");
11077         i_attname = PQfnumber(res, "attname");
11078         while (ncomments > 0)
11079         {
11080                 const char *attname;
11081
11082                 attname = NULL;
11083                 for (i = 0; i < ntups; i++)
11084                 {
11085                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11086                         {
11087                                 attname = PQgetvalue(res, i, i_attname);
11088                                 break;
11089                         }
11090                 }
11091                 if (attname)                    /* just in case we don't find it */
11092                 {
11093                         const char *descr = comments->descr;
11094
11095                         resetPQExpBuffer(target);
11096                         appendPQExpBuffer(target, "COLUMN %s.",
11097                                                           fmtId(tyinfo->dobj.name));
11098                         appendPQExpBufferStr(target, fmtId(attname));
11099
11100                         resetPQExpBuffer(query);
11101                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11102                                                           fmtQualifiedDumpable(tyinfo));
11103                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11104                         appendStringLiteralAH(query, descr, fout);
11105                         appendPQExpBufferStr(query, ";\n");
11106
11107                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11108                                                  target->data,
11109                                                  tyinfo->dobj.namespace->dobj.name,
11110                                                  NULL, tyinfo->rolname,
11111                                                  "COMMENT", SECTION_NONE,
11112                                                  query->data, "", NULL,
11113                                                  &(tyinfo->dobj.dumpId), 1,
11114                                                  NULL, NULL);
11115                 }
11116
11117                 comments++;
11118                 ncomments--;
11119         }
11120
11121         PQclear(res);
11122         destroyPQExpBuffer(query);
11123         destroyPQExpBuffer(target);
11124 }
11125
11126 /*
11127  * dumpShellType
11128  *        writes out to fout the queries to create a shell type
11129  *
11130  * We dump a shell definition in advance of the I/O functions for the type.
11131  */
11132 static void
11133 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11134 {
11135         DumpOptions *dopt = fout->dopt;
11136         PQExpBuffer q;
11137
11138         /* Skip if not to be dumped */
11139         if (!stinfo->dobj.dump || dopt->dataOnly)
11140                 return;
11141
11142         q = createPQExpBuffer();
11143
11144         /*
11145          * Note the lack of a DROP command for the shell type; any required DROP
11146          * is driven off the base type entry, instead.  This interacts with
11147          * _printTocEntry()'s use of the presence of a DROP command to decide
11148          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11149          * the shell type's owner immediately on creation; that should happen only
11150          * after it's filled in, otherwise the backend complains.
11151          */
11152
11153         if (dopt->binary_upgrade)
11154                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11155                                                                                                  stinfo->baseType->dobj.catId.oid,
11156                                                                                                  false);
11157
11158         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11159                                           fmtQualifiedDumpable(stinfo));
11160
11161         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11162                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11163                                          stinfo->dobj.name,
11164                                          stinfo->dobj.namespace->dobj.name,
11165                                          NULL,
11166                                          stinfo->baseType->rolname,
11167                                          "SHELL TYPE", SECTION_PRE_DATA,
11168                                          q->data, "", NULL,
11169                                          NULL, 0,
11170                                          NULL, NULL);
11171
11172         destroyPQExpBuffer(q);
11173 }
11174
11175 /*
11176  * dumpProcLang
11177  *                writes out to fout the queries to recreate a user-defined
11178  *                procedural language
11179  */
11180 static void
11181 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11182 {
11183         DumpOptions *dopt = fout->dopt;
11184         PQExpBuffer defqry;
11185         PQExpBuffer delqry;
11186         bool            useParams;
11187         char       *qlanname;
11188         FuncInfo   *funcInfo;
11189         FuncInfo   *inlineInfo = NULL;
11190         FuncInfo   *validatorInfo = NULL;
11191
11192         /* Skip if not to be dumped */
11193         if (!plang->dobj.dump || dopt->dataOnly)
11194                 return;
11195
11196         /*
11197          * Try to find the support function(s).  It is not an error if we don't
11198          * find them --- if the functions are in the pg_catalog schema, as is
11199          * standard in 8.1 and up, then we won't have loaded them. (In this case
11200          * we will emit a parameterless CREATE LANGUAGE command, which will
11201          * require PL template knowledge in the backend to reload.)
11202          */
11203
11204         funcInfo = findFuncByOid(plang->lanplcallfoid);
11205         if (funcInfo != NULL && !funcInfo->dobj.dump)
11206                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11207
11208         if (OidIsValid(plang->laninline))
11209         {
11210                 inlineInfo = findFuncByOid(plang->laninline);
11211                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11212                         inlineInfo = NULL;
11213         }
11214
11215         if (OidIsValid(plang->lanvalidator))
11216         {
11217                 validatorInfo = findFuncByOid(plang->lanvalidator);
11218                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11219                         validatorInfo = NULL;
11220         }
11221
11222         /*
11223          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11224          * with parameters.  Otherwise, we'll write a parameterless command, which
11225          * will rely on data from pg_pltemplate.
11226          */
11227         useParams = (funcInfo != NULL &&
11228                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11229                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11230
11231         defqry = createPQExpBuffer();
11232         delqry = createPQExpBuffer();
11233
11234         qlanname = pg_strdup(fmtId(plang->dobj.name));
11235
11236         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11237                                           qlanname);
11238
11239         if (useParams)
11240         {
11241                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11242                                                   plang->lanpltrusted ? "TRUSTED " : "",
11243                                                   qlanname);
11244                 appendPQExpBuffer(defqry, " HANDLER %s",
11245                                                   fmtQualifiedDumpable(funcInfo));
11246                 if (OidIsValid(plang->laninline))
11247                         appendPQExpBuffer(defqry, " INLINE %s",
11248                                                           fmtQualifiedDumpable(inlineInfo));
11249                 if (OidIsValid(plang->lanvalidator))
11250                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11251                                                           fmtQualifiedDumpable(validatorInfo));
11252         }
11253         else
11254         {
11255                 /*
11256                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11257                  * command will not fail if the language is preinstalled in the target
11258                  * database.  We restrict the use of REPLACE to this case so as to
11259                  * eliminate the risk of replacing a language with incompatible
11260                  * parameter settings: this command will only succeed at all if there
11261                  * is a pg_pltemplate entry, and if there is one, the existing entry
11262                  * must match it too.
11263                  */
11264                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11265                                                   qlanname);
11266         }
11267         appendPQExpBufferStr(defqry, ";\n");
11268
11269         if (dopt->binary_upgrade)
11270                 binary_upgrade_extension_member(defqry, &plang->dobj,
11271                                                                                 "LANGUAGE", qlanname, NULL);
11272
11273         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11274                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11275                                          plang->dobj.name,
11276                                          NULL, NULL, plang->lanowner,
11277                                          "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11278                                          defqry->data, delqry->data, NULL,
11279                                          NULL, 0,
11280                                          NULL, NULL);
11281
11282         /* Dump Proc Lang Comments and Security Labels */
11283         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11284                 dumpComment(fout, "LANGUAGE", qlanname,
11285                                         NULL, plang->lanowner,
11286                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11287
11288         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11289                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11290                                          NULL, plang->lanowner,
11291                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11292
11293         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11294                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11295                                 qlanname, NULL, NULL,
11296                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11297                                 plang->initlanacl, plang->initrlanacl);
11298
11299         free(qlanname);
11300
11301         destroyPQExpBuffer(defqry);
11302         destroyPQExpBuffer(delqry);
11303 }
11304
11305 /*
11306  * format_function_arguments: generate function name and argument list
11307  *
11308  * This is used when we can rely on pg_get_function_arguments to format
11309  * the argument list.  Note, however, that pg_get_function_arguments
11310  * does not special-case zero-argument aggregates.
11311  */
11312 static char *
11313 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11314 {
11315         PQExpBufferData fn;
11316
11317         initPQExpBuffer(&fn);
11318         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11319         if (is_agg && finfo->nargs == 0)
11320                 appendPQExpBufferStr(&fn, "(*)");
11321         else
11322                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11323         return fn.data;
11324 }
11325
11326 /*
11327  * format_function_arguments_old: generate function name and argument list
11328  *
11329  * The argument type names are qualified if needed.  The function name
11330  * is never qualified.
11331  *
11332  * This is used only with pre-8.4 servers, so we aren't expecting to see
11333  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11334  *
11335  * Any or all of allargtypes, argmodes, argnames may be NULL.
11336  */
11337 static char *
11338 format_function_arguments_old(Archive *fout,
11339                                                           FuncInfo *finfo, int nallargs,
11340                                                           char **allargtypes,
11341                                                           char **argmodes,
11342                                                           char **argnames)
11343 {
11344         PQExpBufferData fn;
11345         int                     j;
11346
11347         initPQExpBuffer(&fn);
11348         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11349         for (j = 0; j < nallargs; j++)
11350         {
11351                 Oid                     typid;
11352                 char       *typname;
11353                 const char *argmode;
11354                 const char *argname;
11355
11356                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11357                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11358
11359                 if (argmodes)
11360                 {
11361                         switch (argmodes[j][0])
11362                         {
11363                                 case PROARGMODE_IN:
11364                                         argmode = "";
11365                                         break;
11366                                 case PROARGMODE_OUT:
11367                                         argmode = "OUT ";
11368                                         break;
11369                                 case PROARGMODE_INOUT:
11370                                         argmode = "INOUT ";
11371                                         break;
11372                                 default:
11373                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11374                                         argmode = "";
11375                                         break;
11376                         }
11377                 }
11378                 else
11379                         argmode = "";
11380
11381                 argname = argnames ? argnames[j] : (char *) NULL;
11382                 if (argname && argname[0] == '\0')
11383                         argname = NULL;
11384
11385                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11386                                                   (j > 0) ? ", " : "",
11387                                                   argmode,
11388                                                   argname ? fmtId(argname) : "",
11389                                                   argname ? " " : "",
11390                                                   typname);
11391                 free(typname);
11392         }
11393         appendPQExpBufferChar(&fn, ')');
11394         return fn.data;
11395 }
11396
11397 /*
11398  * format_function_signature: generate function name and argument list
11399  *
11400  * This is like format_function_arguments_old except that only a minimal
11401  * list of input argument types is generated; this is sufficient to
11402  * reference the function, but not to define it.
11403  *
11404  * If honor_quotes is false then the function name is never quoted.
11405  * This is appropriate for use in TOC tags, but not in SQL commands.
11406  */
11407 static char *
11408 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11409 {
11410         PQExpBufferData fn;
11411         int                     j;
11412
11413         initPQExpBuffer(&fn);
11414         if (honor_quotes)
11415                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11416         else
11417                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11418         for (j = 0; j < finfo->nargs; j++)
11419         {
11420                 char       *typname;
11421
11422                 if (j > 0)
11423                         appendPQExpBufferStr(&fn, ", ");
11424
11425                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11426                                                                            zeroAsOpaque);
11427                 appendPQExpBufferStr(&fn, typname);
11428                 free(typname);
11429         }
11430         appendPQExpBufferChar(&fn, ')');
11431         return fn.data;
11432 }
11433
11434
11435 /*
11436  * dumpFunc:
11437  *        dump out one function
11438  */
11439 static void
11440 dumpFunc(Archive *fout, FuncInfo *finfo)
11441 {
11442         DumpOptions *dopt = fout->dopt;
11443         PQExpBuffer query;
11444         PQExpBuffer q;
11445         PQExpBuffer delqry;
11446         PQExpBuffer asPart;
11447         PGresult   *res;
11448         char       *funcsig;            /* identity signature */
11449         char       *funcfullsig = NULL; /* full signature */
11450         char       *funcsig_tag;
11451         char       *proretset;
11452         char       *prosrc;
11453         char       *probin;
11454         char       *funcargs;
11455         char       *funciargs;
11456         char       *funcresult;
11457         char       *proallargtypes;
11458         char       *proargmodes;
11459         char       *proargnames;
11460         char       *protrftypes;
11461         char       *prokind;
11462         char       *provolatile;
11463         char       *proisstrict;
11464         char       *prosecdef;
11465         char       *proleakproof;
11466         char       *proconfig;
11467         char       *procost;
11468         char       *prorows;
11469         char       *proparallel;
11470         char       *lanname;
11471         char       *rettypename;
11472         int                     nallargs;
11473         char      **allargtypes = NULL;
11474         char      **argmodes = NULL;
11475         char      **argnames = NULL;
11476         char      **configitems = NULL;
11477         int                     nconfigitems = 0;
11478         const char *keyword;
11479         int                     i;
11480
11481         /* Skip if not to be dumped */
11482         if (!finfo->dobj.dump || dopt->dataOnly)
11483                 return;
11484
11485         query = createPQExpBuffer();
11486         q = createPQExpBuffer();
11487         delqry = createPQExpBuffer();
11488         asPart = createPQExpBuffer();
11489
11490         /* Fetch function-specific details */
11491         if (fout->remoteVersion >= 110000)
11492         {
11493                 /*
11494                  * prokind was added in 11
11495                  */
11496                 appendPQExpBuffer(query,
11497                                                   "SELECT proretset, prosrc, probin, "
11498                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11499                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11500                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11501                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11502                                                   "prokind, provolatile, proisstrict, prosecdef, "
11503                                                   "proleakproof, proconfig, procost, prorows, "
11504                                                   "proparallel, "
11505                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11506                                                   "FROM pg_catalog.pg_proc "
11507                                                   "WHERE oid = '%u'::pg_catalog.oid",
11508                                                   finfo->dobj.catId.oid);
11509         }
11510         else if (fout->remoteVersion >= 90600)
11511         {
11512                 /*
11513                  * proparallel was added in 9.6
11514                  */
11515                 appendPQExpBuffer(query,
11516                                                   "SELECT proretset, prosrc, probin, "
11517                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11518                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11519                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11520                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11521                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11522                                                   "provolatile, proisstrict, prosecdef, "
11523                                                   "proleakproof, proconfig, procost, prorows, "
11524                                                   "proparallel, "
11525                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11526                                                   "FROM pg_catalog.pg_proc "
11527                                                   "WHERE oid = '%u'::pg_catalog.oid",
11528                                                   finfo->dobj.catId.oid);
11529         }
11530         else if (fout->remoteVersion >= 90500)
11531         {
11532                 /*
11533                  * protrftypes was added in 9.5
11534                  */
11535                 appendPQExpBuffer(query,
11536                                                   "SELECT proretset, prosrc, probin, "
11537                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11538                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11539                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11540                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11541                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11542                                                   "provolatile, proisstrict, prosecdef, "
11543                                                   "proleakproof, proconfig, procost, prorows, "
11544                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11545                                                   "FROM pg_catalog.pg_proc "
11546                                                   "WHERE oid = '%u'::pg_catalog.oid",
11547                                                   finfo->dobj.catId.oid);
11548         }
11549         else if (fout->remoteVersion >= 90200)
11550         {
11551                 /*
11552                  * proleakproof was added in 9.2
11553                  */
11554                 appendPQExpBuffer(query,
11555                                                   "SELECT proretset, prosrc, probin, "
11556                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11557                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11558                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11559                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11560                                                   "provolatile, proisstrict, prosecdef, "
11561                                                   "proleakproof, proconfig, procost, prorows, "
11562                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11563                                                   "FROM pg_catalog.pg_proc "
11564                                                   "WHERE oid = '%u'::pg_catalog.oid",
11565                                                   finfo->dobj.catId.oid);
11566         }
11567         else if (fout->remoteVersion >= 80400)
11568         {
11569                 /*
11570                  * In 8.4 and up we rely on pg_get_function_arguments and
11571                  * pg_get_function_result instead of examining proallargtypes etc.
11572                  */
11573                 appendPQExpBuffer(query,
11574                                                   "SELECT proretset, prosrc, probin, "
11575                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11576                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11577                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11578                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11579                                                   "provolatile, proisstrict, prosecdef, "
11580                                                   "false AS proleakproof, "
11581                                                   " proconfig, procost, prorows, "
11582                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11583                                                   "FROM pg_catalog.pg_proc "
11584                                                   "WHERE oid = '%u'::pg_catalog.oid",
11585                                                   finfo->dobj.catId.oid);
11586         }
11587         else if (fout->remoteVersion >= 80300)
11588         {
11589                 appendPQExpBuffer(query,
11590                                                   "SELECT proretset, prosrc, probin, "
11591                                                   "proallargtypes, proargmodes, proargnames, "
11592                                                   "'f' AS prokind, "
11593                                                   "provolatile, proisstrict, prosecdef, "
11594                                                   "false AS proleakproof, "
11595                                                   "proconfig, procost, prorows, "
11596                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11597                                                   "FROM pg_catalog.pg_proc "
11598                                                   "WHERE oid = '%u'::pg_catalog.oid",
11599                                                   finfo->dobj.catId.oid);
11600         }
11601         else if (fout->remoteVersion >= 80100)
11602         {
11603                 appendPQExpBuffer(query,
11604                                                   "SELECT proretset, prosrc, probin, "
11605                                                   "proallargtypes, proargmodes, proargnames, "
11606                                                   "'f' AS prokind, "
11607                                                   "provolatile, proisstrict, prosecdef, "
11608                                                   "false AS proleakproof, "
11609                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11610                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11611                                                   "FROM pg_catalog.pg_proc "
11612                                                   "WHERE oid = '%u'::pg_catalog.oid",
11613                                                   finfo->dobj.catId.oid);
11614         }
11615         else
11616         {
11617                 appendPQExpBuffer(query,
11618                                                   "SELECT proretset, prosrc, probin, "
11619                                                   "null AS proallargtypes, "
11620                                                   "null AS proargmodes, "
11621                                                   "proargnames, "
11622                                                   "'f' AS prokind, "
11623                                                   "provolatile, proisstrict, prosecdef, "
11624                                                   "false AS proleakproof, "
11625                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11626                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11627                                                   "FROM pg_catalog.pg_proc "
11628                                                   "WHERE oid = '%u'::pg_catalog.oid",
11629                                                   finfo->dobj.catId.oid);
11630         }
11631
11632         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11633
11634         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11635         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11636         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11637         if (fout->remoteVersion >= 80400)
11638         {
11639                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11640                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11641                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11642                 proallargtypes = proargmodes = proargnames = NULL;
11643         }
11644         else
11645         {
11646                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11647                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11648                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11649                 funcargs = funciargs = funcresult = NULL;
11650         }
11651         if (PQfnumber(res, "protrftypes") != -1)
11652                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11653         else
11654                 protrftypes = NULL;
11655         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11656         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11657         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11658         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11659         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11660         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11661         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11662         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11663
11664         if (PQfnumber(res, "proparallel") != -1)
11665                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11666         else
11667                 proparallel = NULL;
11668
11669         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11670
11671         /*
11672          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11673          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11674          * versions would set it to "-".  There are no known cases in which prosrc
11675          * is unused, so the tests below for "-" are probably useless.
11676          */
11677         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11678         {
11679                 appendPQExpBufferStr(asPart, "AS ");
11680                 appendStringLiteralAH(asPart, probin, fout);
11681                 if (strcmp(prosrc, "-") != 0)
11682                 {
11683                         appendPQExpBufferStr(asPart, ", ");
11684
11685                         /*
11686                          * where we have bin, use dollar quoting if allowed and src
11687                          * contains quote or backslash; else use regular quoting.
11688                          */
11689                         if (dopt->disable_dollar_quoting ||
11690                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11691                                 appendStringLiteralAH(asPart, prosrc, fout);
11692                         else
11693                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11694                 }
11695         }
11696         else
11697         {
11698                 if (strcmp(prosrc, "-") != 0)
11699                 {
11700                         appendPQExpBufferStr(asPart, "AS ");
11701                         /* with no bin, dollar quote src unconditionally if allowed */
11702                         if (dopt->disable_dollar_quoting)
11703                                 appendStringLiteralAH(asPart, prosrc, fout);
11704                         else
11705                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11706                 }
11707         }
11708
11709         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11710
11711         if (proallargtypes && *proallargtypes)
11712         {
11713                 int                     nitems = 0;
11714
11715                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11716                         nitems < finfo->nargs)
11717                 {
11718                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11719                         if (allargtypes)
11720                                 free(allargtypes);
11721                         allargtypes = NULL;
11722                 }
11723                 else
11724                         nallargs = nitems;
11725         }
11726
11727         if (proargmodes && *proargmodes)
11728         {
11729                 int                     nitems = 0;
11730
11731                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11732                         nitems != nallargs)
11733                 {
11734                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11735                         if (argmodes)
11736                                 free(argmodes);
11737                         argmodes = NULL;
11738                 }
11739         }
11740
11741         if (proargnames && *proargnames)
11742         {
11743                 int                     nitems = 0;
11744
11745                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11746                         nitems != nallargs)
11747                 {
11748                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11749                         if (argnames)
11750                                 free(argnames);
11751                         argnames = NULL;
11752                 }
11753         }
11754
11755         if (proconfig && *proconfig)
11756         {
11757                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11758                 {
11759                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11760                         if (configitems)
11761                                 free(configitems);
11762                         configitems = NULL;
11763                         nconfigitems = 0;
11764                 }
11765         }
11766
11767         if (funcargs)
11768         {
11769                 /* 8.4 or later; we rely on server-side code for most of the work */
11770                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11771                 funcsig = format_function_arguments(finfo, funciargs, false);
11772         }
11773         else
11774                 /* pre-8.4, do it ourselves */
11775                 funcsig = format_function_arguments_old(fout,
11776                                                                                                 finfo, nallargs, allargtypes,
11777                                                                                                 argmodes, argnames);
11778
11779         funcsig_tag = format_function_signature(fout, finfo, false);
11780
11781         if (prokind[0] == PROKIND_PROCEDURE)
11782                 keyword = "PROCEDURE";
11783         else
11784                 keyword = "FUNCTION";   /* works for window functions too */
11785
11786         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11787                                           keyword,
11788                                           fmtId(finfo->dobj.namespace->dobj.name),
11789                                           funcsig);
11790
11791         appendPQExpBuffer(q, "CREATE %s %s.%s",
11792                                           keyword,
11793                                           fmtId(finfo->dobj.namespace->dobj.name),
11794                                           funcfullsig ? funcfullsig :
11795                                           funcsig);
11796
11797         if (prokind[0] == PROKIND_PROCEDURE)
11798                  /* no result type to output */ ;
11799         else if (funcresult)
11800                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11801         else
11802         {
11803                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11804                                                                                    zeroAsOpaque);
11805                 appendPQExpBuffer(q, " RETURNS %s%s",
11806                                                   (proretset[0] == 't') ? "SETOF " : "",
11807                                                   rettypename);
11808                 free(rettypename);
11809         }
11810
11811         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11812
11813         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11814         {
11815                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11816                 int                     i;
11817
11818                 appendPQExpBufferStr(q, " TRANSFORM ");
11819                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11820                 for (i = 0; typeids[i]; i++)
11821                 {
11822                         if (i != 0)
11823                                 appendPQExpBufferStr(q, ", ");
11824                         appendPQExpBuffer(q, "FOR TYPE %s",
11825                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11826                 }
11827         }
11828
11829         if (prokind[0] == PROKIND_WINDOW)
11830                 appendPQExpBufferStr(q, " WINDOW");
11831
11832         if (provolatile[0] != PROVOLATILE_VOLATILE)
11833         {
11834                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11835                         appendPQExpBufferStr(q, " IMMUTABLE");
11836                 else if (provolatile[0] == PROVOLATILE_STABLE)
11837                         appendPQExpBufferStr(q, " STABLE");
11838                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11839                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11840                                                   finfo->dobj.name);
11841         }
11842
11843         if (proisstrict[0] == 't')
11844                 appendPQExpBufferStr(q, " STRICT");
11845
11846         if (prosecdef[0] == 't')
11847                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11848
11849         if (proleakproof[0] == 't')
11850                 appendPQExpBufferStr(q, " LEAKPROOF");
11851
11852         /*
11853          * COST and ROWS are emitted only if present and not default, so as not to
11854          * break backwards-compatibility of the dump without need.  Keep this code
11855          * in sync with the defaults in functioncmds.c.
11856          */
11857         if (strcmp(procost, "0") != 0)
11858         {
11859                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11860                 {
11861                         /* default cost is 1 */
11862                         if (strcmp(procost, "1") != 0)
11863                                 appendPQExpBuffer(q, " COST %s", procost);
11864                 }
11865                 else
11866                 {
11867                         /* default cost is 100 */
11868                         if (strcmp(procost, "100") != 0)
11869                                 appendPQExpBuffer(q, " COST %s", procost);
11870                 }
11871         }
11872         if (proretset[0] == 't' &&
11873                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11874                 appendPQExpBuffer(q, " ROWS %s", prorows);
11875
11876         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11877         {
11878                 if (proparallel[0] == PROPARALLEL_SAFE)
11879                         appendPQExpBufferStr(q, " PARALLEL SAFE");
11880                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11881                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11882                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
11883                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11884                                                   finfo->dobj.name);
11885         }
11886
11887         for (i = 0; i < nconfigitems; i++)
11888         {
11889                 /* we feel free to scribble on configitems[] here */
11890                 char       *configitem = configitems[i];
11891                 char       *pos;
11892
11893                 pos = strchr(configitem, '=');
11894                 if (pos == NULL)
11895                         continue;
11896                 *pos++ = '\0';
11897                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
11898
11899                 /*
11900                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
11901                  * by flatten_set_variable_args() before they were put into the
11902                  * proconfig array.  However, because the quoting rules used there
11903                  * aren't exactly like SQL's, we have to break the list value apart
11904                  * and then quote the elements as string literals.  (The elements may
11905                  * be double-quoted as-is, but we can't just feed them to the SQL
11906                  * parser; it would do the wrong thing with elements that are
11907                  * zero-length or longer than NAMEDATALEN.)
11908                  *
11909                  * Variables that are not so marked should just be emitted as simple
11910                  * string literals.  If the variable is not known to
11911                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
11912                  * to use GUC_LIST_QUOTE for extension variables.
11913                  */
11914                 if (variable_is_guc_list_quote(configitem))
11915                 {
11916                         char      **namelist;
11917                         char      **nameptr;
11918
11919                         /* Parse string into list of identifiers */
11920                         /* this shouldn't fail really */
11921                         if (SplitGUCList(pos, ',', &namelist))
11922                         {
11923                                 for (nameptr = namelist; *nameptr; nameptr++)
11924                                 {
11925                                         if (nameptr != namelist)
11926                                                 appendPQExpBufferStr(q, ", ");
11927                                         appendStringLiteralAH(q, *nameptr, fout);
11928                                 }
11929                         }
11930                         pg_free(namelist);
11931                 }
11932                 else
11933                         appendStringLiteralAH(q, pos, fout);
11934         }
11935
11936         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
11937
11938         if (dopt->binary_upgrade)
11939                 binary_upgrade_extension_member(q, &finfo->dobj,
11940                                                                                 keyword, funcsig,
11941                                                                                 finfo->dobj.namespace->dobj.name);
11942
11943         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11944                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11945                                          funcsig_tag,
11946                                          finfo->dobj.namespace->dobj.name,
11947                                          NULL,
11948                                          finfo->rolname,
11949                                          keyword, SECTION_PRE_DATA,
11950                                          q->data, delqry->data, NULL,
11951                                          NULL, 0,
11952                                          NULL, NULL);
11953
11954         /* Dump Function Comments and Security Labels */
11955         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11956                 dumpComment(fout, keyword, funcsig,
11957                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
11958                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
11959
11960         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11961                 dumpSecLabel(fout, keyword, funcsig,
11962                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
11963                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
11964
11965         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
11966                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
11967                                 funcsig, NULL,
11968                                 finfo->dobj.namespace->dobj.name,
11969                                 finfo->rolname, finfo->proacl, finfo->rproacl,
11970                                 finfo->initproacl, finfo->initrproacl);
11971
11972         PQclear(res);
11973
11974         destroyPQExpBuffer(query);
11975         destroyPQExpBuffer(q);
11976         destroyPQExpBuffer(delqry);
11977         destroyPQExpBuffer(asPart);
11978         free(funcsig);
11979         if (funcfullsig)
11980                 free(funcfullsig);
11981         free(funcsig_tag);
11982         if (allargtypes)
11983                 free(allargtypes);
11984         if (argmodes)
11985                 free(argmodes);
11986         if (argnames)
11987                 free(argnames);
11988         if (configitems)
11989                 free(configitems);
11990 }
11991
11992
11993 /*
11994  * Dump a user-defined cast
11995  */
11996 static void
11997 dumpCast(Archive *fout, CastInfo *cast)
11998 {
11999         DumpOptions *dopt = fout->dopt;
12000         PQExpBuffer defqry;
12001         PQExpBuffer delqry;
12002         PQExpBuffer labelq;
12003         PQExpBuffer castargs;
12004         FuncInfo   *funcInfo = NULL;
12005         char       *sourceType;
12006         char       *targetType;
12007
12008         /* Skip if not to be dumped */
12009         if (!cast->dobj.dump || dopt->dataOnly)
12010                 return;
12011
12012         /* Cannot dump if we don't have the cast function's info */
12013         if (OidIsValid(cast->castfunc))
12014         {
12015                 funcInfo = findFuncByOid(cast->castfunc);
12016                 if (funcInfo == NULL)
12017                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12018                                                   cast->castfunc);
12019         }
12020
12021         defqry = createPQExpBuffer();
12022         delqry = createPQExpBuffer();
12023         labelq = createPQExpBuffer();
12024         castargs = createPQExpBuffer();
12025
12026         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12027         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12028         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12029                                           sourceType, targetType);
12030
12031         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12032                                           sourceType, targetType);
12033
12034         switch (cast->castmethod)
12035         {
12036                 case COERCION_METHOD_BINARY:
12037                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12038                         break;
12039                 case COERCION_METHOD_INOUT:
12040                         appendPQExpBufferStr(defqry, "WITH INOUT");
12041                         break;
12042                 case COERCION_METHOD_FUNCTION:
12043                         if (funcInfo)
12044                         {
12045                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12046
12047                                 /*
12048                                  * Always qualify the function name (format_function_signature
12049                                  * won't qualify it).
12050                                  */
12051                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12052                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12053                                 free(fsig);
12054                         }
12055                         else
12056                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12057                         break;
12058                 default:
12059                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12060         }
12061
12062         if (cast->castcontext == 'a')
12063                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12064         else if (cast->castcontext == 'i')
12065                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12066         appendPQExpBufferStr(defqry, ";\n");
12067
12068         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12069                                           sourceType, targetType);
12070
12071         appendPQExpBuffer(castargs, "(%s AS %s)",
12072                                           sourceType, targetType);
12073
12074         if (dopt->binary_upgrade)
12075                 binary_upgrade_extension_member(defqry, &cast->dobj,
12076                                                                                 "CAST", castargs->data, NULL);
12077
12078         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12079                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12080                                          labelq->data,
12081                                          NULL, NULL, "",
12082                                          "CAST", SECTION_PRE_DATA,
12083                                          defqry->data, delqry->data, NULL,
12084                                          NULL, 0,
12085                                          NULL, NULL);
12086
12087         /* Dump Cast Comments */
12088         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12089                 dumpComment(fout, "CAST", castargs->data,
12090                                         NULL, "",
12091                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12092
12093         free(sourceType);
12094         free(targetType);
12095
12096         destroyPQExpBuffer(defqry);
12097         destroyPQExpBuffer(delqry);
12098         destroyPQExpBuffer(labelq);
12099         destroyPQExpBuffer(castargs);
12100 }
12101
12102 /*
12103  * Dump a transform
12104  */
12105 static void
12106 dumpTransform(Archive *fout, TransformInfo *transform)
12107 {
12108         DumpOptions *dopt = fout->dopt;
12109         PQExpBuffer defqry;
12110         PQExpBuffer delqry;
12111         PQExpBuffer labelq;
12112         PQExpBuffer transformargs;
12113         FuncInfo   *fromsqlFuncInfo = NULL;
12114         FuncInfo   *tosqlFuncInfo = NULL;
12115         char       *lanname;
12116         char       *transformType;
12117
12118         /* Skip if not to be dumped */
12119         if (!transform->dobj.dump || dopt->dataOnly)
12120                 return;
12121
12122         /* Cannot dump if we don't have the transform functions' info */
12123         if (OidIsValid(transform->trffromsql))
12124         {
12125                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12126                 if (fromsqlFuncInfo == NULL)
12127                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12128                                                   transform->trffromsql);
12129         }
12130         if (OidIsValid(transform->trftosql))
12131         {
12132                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12133                 if (tosqlFuncInfo == NULL)
12134                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12135                                                   transform->trftosql);
12136         }
12137
12138         defqry = createPQExpBuffer();
12139         delqry = createPQExpBuffer();
12140         labelq = createPQExpBuffer();
12141         transformargs = createPQExpBuffer();
12142
12143         lanname = get_language_name(fout, transform->trflang);
12144         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12145
12146         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12147                                           transformType, lanname);
12148
12149         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12150                                           transformType, lanname);
12151
12152         if (!transform->trffromsql && !transform->trftosql)
12153                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12154
12155         if (transform->trffromsql)
12156         {
12157                 if (fromsqlFuncInfo)
12158                 {
12159                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12160
12161                         /*
12162                          * Always qualify the function name (format_function_signature
12163                          * won't qualify it).
12164                          */
12165                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12166                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12167                         free(fsig);
12168                 }
12169                 else
12170                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12171         }
12172
12173         if (transform->trftosql)
12174         {
12175                 if (transform->trffromsql)
12176                         appendPQExpBuffer(defqry, ", ");
12177
12178                 if (tosqlFuncInfo)
12179                 {
12180                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12181
12182                         /*
12183                          * Always qualify the function name (format_function_signature
12184                          * won't qualify it).
12185                          */
12186                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12187                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12188                         free(fsig);
12189                 }
12190                 else
12191                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12192         }
12193
12194         appendPQExpBuffer(defqry, ");\n");
12195
12196         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12197                                           transformType, lanname);
12198
12199         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12200                                           transformType, lanname);
12201
12202         if (dopt->binary_upgrade)
12203                 binary_upgrade_extension_member(defqry, &transform->dobj,
12204                                                                                 "TRANSFORM", transformargs->data, NULL);
12205
12206         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12207                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12208                                          labelq->data,
12209                                          NULL, NULL, "",
12210                                          "TRANSFORM", SECTION_PRE_DATA,
12211                                          defqry->data, delqry->data, NULL,
12212                                          transform->dobj.dependencies, transform->dobj.nDeps,
12213                                          NULL, NULL);
12214
12215         /* Dump Transform Comments */
12216         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12217                 dumpComment(fout, "TRANSFORM", transformargs->data,
12218                                         NULL, "",
12219                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12220
12221         free(lanname);
12222         free(transformType);
12223         destroyPQExpBuffer(defqry);
12224         destroyPQExpBuffer(delqry);
12225         destroyPQExpBuffer(labelq);
12226         destroyPQExpBuffer(transformargs);
12227 }
12228
12229
12230 /*
12231  * dumpOpr
12232  *        write out a single operator definition
12233  */
12234 static void
12235 dumpOpr(Archive *fout, OprInfo *oprinfo)
12236 {
12237         DumpOptions *dopt = fout->dopt;
12238         PQExpBuffer query;
12239         PQExpBuffer q;
12240         PQExpBuffer delq;
12241         PQExpBuffer oprid;
12242         PQExpBuffer details;
12243         PGresult   *res;
12244         int                     i_oprkind;
12245         int                     i_oprcode;
12246         int                     i_oprleft;
12247         int                     i_oprright;
12248         int                     i_oprcom;
12249         int                     i_oprnegate;
12250         int                     i_oprrest;
12251         int                     i_oprjoin;
12252         int                     i_oprcanmerge;
12253         int                     i_oprcanhash;
12254         char       *oprkind;
12255         char       *oprcode;
12256         char       *oprleft;
12257         char       *oprright;
12258         char       *oprcom;
12259         char       *oprnegate;
12260         char       *oprrest;
12261         char       *oprjoin;
12262         char       *oprcanmerge;
12263         char       *oprcanhash;
12264         char       *oprregproc;
12265         char       *oprref;
12266
12267         /* Skip if not to be dumped */
12268         if (!oprinfo->dobj.dump || dopt->dataOnly)
12269                 return;
12270
12271         /*
12272          * some operators are invalid because they were the result of user
12273          * defining operators before commutators exist
12274          */
12275         if (!OidIsValid(oprinfo->oprcode))
12276                 return;
12277
12278         query = createPQExpBuffer();
12279         q = createPQExpBuffer();
12280         delq = createPQExpBuffer();
12281         oprid = createPQExpBuffer();
12282         details = createPQExpBuffer();
12283
12284         if (fout->remoteVersion >= 80300)
12285         {
12286                 appendPQExpBuffer(query, "SELECT oprkind, "
12287                                                   "oprcode::pg_catalog.regprocedure, "
12288                                                   "oprleft::pg_catalog.regtype, "
12289                                                   "oprright::pg_catalog.regtype, "
12290                                                   "oprcom, "
12291                                                   "oprnegate, "
12292                                                   "oprrest::pg_catalog.regprocedure, "
12293                                                   "oprjoin::pg_catalog.regprocedure, "
12294                                                   "oprcanmerge, oprcanhash "
12295                                                   "FROM pg_catalog.pg_operator "
12296                                                   "WHERE oid = '%u'::pg_catalog.oid",
12297                                                   oprinfo->dobj.catId.oid);
12298         }
12299         else
12300         {
12301                 appendPQExpBuffer(query, "SELECT oprkind, "
12302                                                   "oprcode::pg_catalog.regprocedure, "
12303                                                   "oprleft::pg_catalog.regtype, "
12304                                                   "oprright::pg_catalog.regtype, "
12305                                                   "oprcom, "
12306                                                   "oprnegate, "
12307                                                   "oprrest::pg_catalog.regprocedure, "
12308                                                   "oprjoin::pg_catalog.regprocedure, "
12309                                                   "(oprlsortop != 0) AS oprcanmerge, "
12310                                                   "oprcanhash "
12311                                                   "FROM pg_catalog.pg_operator "
12312                                                   "WHERE oid = '%u'::pg_catalog.oid",
12313                                                   oprinfo->dobj.catId.oid);
12314         }
12315
12316         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12317
12318         i_oprkind = PQfnumber(res, "oprkind");
12319         i_oprcode = PQfnumber(res, "oprcode");
12320         i_oprleft = PQfnumber(res, "oprleft");
12321         i_oprright = PQfnumber(res, "oprright");
12322         i_oprcom = PQfnumber(res, "oprcom");
12323         i_oprnegate = PQfnumber(res, "oprnegate");
12324         i_oprrest = PQfnumber(res, "oprrest");
12325         i_oprjoin = PQfnumber(res, "oprjoin");
12326         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12327         i_oprcanhash = PQfnumber(res, "oprcanhash");
12328
12329         oprkind = PQgetvalue(res, 0, i_oprkind);
12330         oprcode = PQgetvalue(res, 0, i_oprcode);
12331         oprleft = PQgetvalue(res, 0, i_oprleft);
12332         oprright = PQgetvalue(res, 0, i_oprright);
12333         oprcom = PQgetvalue(res, 0, i_oprcom);
12334         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12335         oprrest = PQgetvalue(res, 0, i_oprrest);
12336         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12337         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12338         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12339
12340         oprregproc = convertRegProcReference(fout, oprcode);
12341         if (oprregproc)
12342         {
12343                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12344                 free(oprregproc);
12345         }
12346
12347         appendPQExpBuffer(oprid, "%s (",
12348                                           oprinfo->dobj.name);
12349
12350         /*
12351          * right unary means there's a left arg and left unary means there's a
12352          * right arg
12353          */
12354         if (strcmp(oprkind, "r") == 0 ||
12355                 strcmp(oprkind, "b") == 0)
12356         {
12357                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12358                 appendPQExpBufferStr(oprid, oprleft);
12359         }
12360         else
12361                 appendPQExpBufferStr(oprid, "NONE");
12362
12363         if (strcmp(oprkind, "l") == 0 ||
12364                 strcmp(oprkind, "b") == 0)
12365         {
12366                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12367                 appendPQExpBuffer(oprid, ", %s)", oprright);
12368         }
12369         else
12370                 appendPQExpBufferStr(oprid, ", NONE)");
12371
12372         oprref = getFormattedOperatorName(fout, oprcom);
12373         if (oprref)
12374         {
12375                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12376                 free(oprref);
12377         }
12378
12379         oprref = getFormattedOperatorName(fout, oprnegate);
12380         if (oprref)
12381         {
12382                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12383                 free(oprref);
12384         }
12385
12386         if (strcmp(oprcanmerge, "t") == 0)
12387                 appendPQExpBufferStr(details, ",\n    MERGES");
12388
12389         if (strcmp(oprcanhash, "t") == 0)
12390                 appendPQExpBufferStr(details, ",\n    HASHES");
12391
12392         oprregproc = convertRegProcReference(fout, oprrest);
12393         if (oprregproc)
12394         {
12395                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12396                 free(oprregproc);
12397         }
12398
12399         oprregproc = convertRegProcReference(fout, oprjoin);
12400         if (oprregproc)
12401         {
12402                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12403                 free(oprregproc);
12404         }
12405
12406         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12407                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12408                                           oprid->data);
12409
12410         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12411                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12412                                           oprinfo->dobj.name, details->data);
12413
12414         if (dopt->binary_upgrade)
12415                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12416                                                                                 "OPERATOR", oprid->data,
12417                                                                                 oprinfo->dobj.namespace->dobj.name);
12418
12419         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12420                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12421                                          oprinfo->dobj.name,
12422                                          oprinfo->dobj.namespace->dobj.name,
12423                                          NULL,
12424                                          oprinfo->rolname,
12425                                          "OPERATOR", SECTION_PRE_DATA,
12426                                          q->data, delq->data, NULL,
12427                                          NULL, 0,
12428                                          NULL, NULL);
12429
12430         /* Dump Operator Comments */
12431         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12432                 dumpComment(fout, "OPERATOR", oprid->data,
12433                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12434                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12435
12436         PQclear(res);
12437
12438         destroyPQExpBuffer(query);
12439         destroyPQExpBuffer(q);
12440         destroyPQExpBuffer(delq);
12441         destroyPQExpBuffer(oprid);
12442         destroyPQExpBuffer(details);
12443 }
12444
12445 /*
12446  * Convert a function reference obtained from pg_operator
12447  *
12448  * Returns allocated string of what to print, or NULL if function references
12449  * is InvalidOid. Returned string is expected to be free'd by the caller.
12450  *
12451  * The input is a REGPROCEDURE display; we have to strip the argument-types
12452  * part.
12453  */
12454 static char *
12455 convertRegProcReference(Archive *fout, const char *proc)
12456 {
12457         char       *name;
12458         char       *paren;
12459         bool            inquote;
12460
12461         /* In all cases "-" means a null reference */
12462         if (strcmp(proc, "-") == 0)
12463                 return NULL;
12464
12465         name = pg_strdup(proc);
12466         /* find non-double-quoted left paren */
12467         inquote = false;
12468         for (paren = name; *paren; paren++)
12469         {
12470                 if (*paren == '(' && !inquote)
12471                 {
12472                         *paren = '\0';
12473                         break;
12474                 }
12475                 if (*paren == '"')
12476                         inquote = !inquote;
12477         }
12478         return name;
12479 }
12480
12481 /*
12482  * getFormattedOperatorName - retrieve the operator name for the
12483  * given operator OID (presented in string form).
12484  *
12485  * Returns an allocated string, or NULL if the given OID is invalid.
12486  * Caller is responsible for free'ing result string.
12487  *
12488  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12489  * useful in commands where the operator's argument types can be inferred from
12490  * context.  We always schema-qualify the name, though.  The predecessor to
12491  * this code tried to skip the schema qualification if possible, but that led
12492  * to wrong results in corner cases, such as if an operator and its negator
12493  * are in different schemas.
12494  */
12495 static char *
12496 getFormattedOperatorName(Archive *fout, const char *oproid)
12497 {
12498         OprInfo    *oprInfo;
12499
12500         /* In all cases "0" means a null reference */
12501         if (strcmp(oproid, "0") == 0)
12502                 return NULL;
12503
12504         oprInfo = findOprByOid(atooid(oproid));
12505         if (oprInfo == NULL)
12506         {
12507                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12508                                   oproid);
12509                 return NULL;
12510         }
12511
12512         return psprintf("OPERATOR(%s.%s)",
12513                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12514                                         oprInfo->dobj.name);
12515 }
12516
12517 /*
12518  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12519  *
12520  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12521  * argument lists of these functions are predetermined.  Note that the
12522  * caller should ensure we are in the proper schema, because the results
12523  * are search path dependent!
12524  */
12525 static char *
12526 convertTSFunction(Archive *fout, Oid funcOid)
12527 {
12528         char       *result;
12529         char            query[128];
12530         PGresult   *res;
12531
12532         snprintf(query, sizeof(query),
12533                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12534         res = ExecuteSqlQueryForSingleRow(fout, query);
12535
12536         result = pg_strdup(PQgetvalue(res, 0, 0));
12537
12538         PQclear(res);
12539
12540         return result;
12541 }
12542
12543 /*
12544  * dumpAccessMethod
12545  *        write out a single access method definition
12546  */
12547 static void
12548 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12549 {
12550         DumpOptions *dopt = fout->dopt;
12551         PQExpBuffer q;
12552         PQExpBuffer delq;
12553         char       *qamname;
12554
12555         /* Skip if not to be dumped */
12556         if (!aminfo->dobj.dump || dopt->dataOnly)
12557                 return;
12558
12559         q = createPQExpBuffer();
12560         delq = createPQExpBuffer();
12561
12562         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12563
12564         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12565
12566         switch (aminfo->amtype)
12567         {
12568                 case AMTYPE_INDEX:
12569                         appendPQExpBuffer(q, "TYPE INDEX ");
12570                         break;
12571                 default:
12572                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12573                                           aminfo->amtype, qamname);
12574                         destroyPQExpBuffer(q);
12575                         destroyPQExpBuffer(delq);
12576                         free(qamname);
12577                         return;
12578         }
12579
12580         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12581
12582         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12583                                           qamname);
12584
12585         if (dopt->binary_upgrade)
12586                 binary_upgrade_extension_member(q, &aminfo->dobj,
12587                                                                                 "ACCESS METHOD", qamname, NULL);
12588
12589         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12590                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12591                                          aminfo->dobj.name,
12592                                          NULL,
12593                                          NULL,
12594                                          "",
12595                                          "ACCESS METHOD", SECTION_PRE_DATA,
12596                                          q->data, delq->data, NULL,
12597                                          NULL, 0,
12598                                          NULL, NULL);
12599
12600         /* Dump Access Method Comments */
12601         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12602                 dumpComment(fout, "ACCESS METHOD", qamname,
12603                                         NULL, "",
12604                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12605
12606         destroyPQExpBuffer(q);
12607         destroyPQExpBuffer(delq);
12608         free(qamname);
12609 }
12610
12611 /*
12612  * dumpOpclass
12613  *        write out a single operator class definition
12614  */
12615 static void
12616 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12617 {
12618         DumpOptions *dopt = fout->dopt;
12619         PQExpBuffer query;
12620         PQExpBuffer q;
12621         PQExpBuffer delq;
12622         PQExpBuffer nameusing;
12623         PGresult   *res;
12624         int                     ntups;
12625         int                     i_opcintype;
12626         int                     i_opckeytype;
12627         int                     i_opcdefault;
12628         int                     i_opcfamily;
12629         int                     i_opcfamilyname;
12630         int                     i_opcfamilynsp;
12631         int                     i_amname;
12632         int                     i_amopstrategy;
12633         int                     i_amopreqcheck;
12634         int                     i_amopopr;
12635         int                     i_sortfamily;
12636         int                     i_sortfamilynsp;
12637         int                     i_amprocnum;
12638         int                     i_amproc;
12639         int                     i_amproclefttype;
12640         int                     i_amprocrighttype;
12641         char       *opcintype;
12642         char       *opckeytype;
12643         char       *opcdefault;
12644         char       *opcfamily;
12645         char       *opcfamilyname;
12646         char       *opcfamilynsp;
12647         char       *amname;
12648         char       *amopstrategy;
12649         char       *amopreqcheck;
12650         char       *amopopr;
12651         char       *sortfamily;
12652         char       *sortfamilynsp;
12653         char       *amprocnum;
12654         char       *amproc;
12655         char       *amproclefttype;
12656         char       *amprocrighttype;
12657         bool            needComma;
12658         int                     i;
12659
12660         /* Skip if not to be dumped */
12661         if (!opcinfo->dobj.dump || dopt->dataOnly)
12662                 return;
12663
12664         query = createPQExpBuffer();
12665         q = createPQExpBuffer();
12666         delq = createPQExpBuffer();
12667         nameusing = createPQExpBuffer();
12668
12669         /* Get additional fields from the pg_opclass row */
12670         if (fout->remoteVersion >= 80300)
12671         {
12672                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12673                                                   "opckeytype::pg_catalog.regtype, "
12674                                                   "opcdefault, opcfamily, "
12675                                                   "opfname AS opcfamilyname, "
12676                                                   "nspname AS opcfamilynsp, "
12677                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12678                                                   "FROM pg_catalog.pg_opclass c "
12679                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12680                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12681                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12682                                                   opcinfo->dobj.catId.oid);
12683         }
12684         else
12685         {
12686                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12687                                                   "opckeytype::pg_catalog.regtype, "
12688                                                   "opcdefault, NULL AS opcfamily, "
12689                                                   "NULL AS opcfamilyname, "
12690                                                   "NULL AS opcfamilynsp, "
12691                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12692                                                   "FROM pg_catalog.pg_opclass "
12693                                                   "WHERE oid = '%u'::pg_catalog.oid",
12694                                                   opcinfo->dobj.catId.oid);
12695         }
12696
12697         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12698
12699         i_opcintype = PQfnumber(res, "opcintype");
12700         i_opckeytype = PQfnumber(res, "opckeytype");
12701         i_opcdefault = PQfnumber(res, "opcdefault");
12702         i_opcfamily = PQfnumber(res, "opcfamily");
12703         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12704         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12705         i_amname = PQfnumber(res, "amname");
12706
12707         /* opcintype may still be needed after we PQclear res */
12708         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12709         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12710         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12711         /* opcfamily will still be needed after we PQclear res */
12712         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12713         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12714         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12715         /* amname will still be needed after we PQclear res */
12716         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12717
12718         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12719                                           fmtQualifiedDumpable(opcinfo));
12720         appendPQExpBuffer(delq, " USING %s;\n",
12721                                           fmtId(amname));
12722
12723         /* Build the fixed portion of the CREATE command */
12724         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12725                                           fmtQualifiedDumpable(opcinfo));
12726         if (strcmp(opcdefault, "t") == 0)
12727                 appendPQExpBufferStr(q, "DEFAULT ");
12728         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12729                                           opcintype,
12730                                           fmtId(amname));
12731         if (strlen(opcfamilyname) > 0)
12732         {
12733                 appendPQExpBufferStr(q, " FAMILY ");
12734                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12735                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12736         }
12737         appendPQExpBufferStr(q, " AS\n    ");
12738
12739         needComma = false;
12740
12741         if (strcmp(opckeytype, "-") != 0)
12742         {
12743                 appendPQExpBuffer(q, "STORAGE %s",
12744                                                   opckeytype);
12745                 needComma = true;
12746         }
12747
12748         PQclear(res);
12749
12750         /*
12751          * Now fetch and print the OPERATOR entries (pg_amop rows).
12752          *
12753          * Print only those opfamily members that are tied to the opclass by
12754          * pg_depend entries.
12755          *
12756          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12757          * older server's opclass in which it is used.  This is to avoid
12758          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12759          * older server and then reload into that old version.  This can go away
12760          * once 8.3 is so old as to not be of interest to anyone.
12761          */
12762         resetPQExpBuffer(query);
12763
12764         if (fout->remoteVersion >= 90100)
12765         {
12766                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12767                                                   "amopopr::pg_catalog.regoperator, "
12768                                                   "opfname AS sortfamily, "
12769                                                   "nspname AS sortfamilynsp "
12770                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12771                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12772                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12773                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12774                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12775                                                   "AND refobjid = '%u'::pg_catalog.oid "
12776                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12777                                                   "ORDER BY amopstrategy",
12778                                                   opcinfo->dobj.catId.oid,
12779                                                   opcfamily);
12780         }
12781         else if (fout->remoteVersion >= 80400)
12782         {
12783                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12784                                                   "amopopr::pg_catalog.regoperator, "
12785                                                   "NULL AS sortfamily, "
12786                                                   "NULL AS sortfamilynsp "
12787                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12788                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12789                                                   "AND refobjid = '%u'::pg_catalog.oid "
12790                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12791                                                   "AND objid = ao.oid "
12792                                                   "ORDER BY amopstrategy",
12793                                                   opcinfo->dobj.catId.oid);
12794         }
12795         else if (fout->remoteVersion >= 80300)
12796         {
12797                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12798                                                   "amopopr::pg_catalog.regoperator, "
12799                                                   "NULL AS sortfamily, "
12800                                                   "NULL AS sortfamilynsp "
12801                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12802                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12803                                                   "AND refobjid = '%u'::pg_catalog.oid "
12804                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12805                                                   "AND objid = ao.oid "
12806                                                   "ORDER BY amopstrategy",
12807                                                   opcinfo->dobj.catId.oid);
12808         }
12809         else
12810         {
12811                 /*
12812                  * Here, we print all entries since there are no opfamilies and hence
12813                  * no loose operators to worry about.
12814                  */
12815                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12816                                                   "amopopr::pg_catalog.regoperator, "
12817                                                   "NULL AS sortfamily, "
12818                                                   "NULL AS sortfamilynsp "
12819                                                   "FROM pg_catalog.pg_amop "
12820                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12821                                                   "ORDER BY amopstrategy",
12822                                                   opcinfo->dobj.catId.oid);
12823         }
12824
12825         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12826
12827         ntups = PQntuples(res);
12828
12829         i_amopstrategy = PQfnumber(res, "amopstrategy");
12830         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12831         i_amopopr = PQfnumber(res, "amopopr");
12832         i_sortfamily = PQfnumber(res, "sortfamily");
12833         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12834
12835         for (i = 0; i < ntups; i++)
12836         {
12837                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12838                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12839                 amopopr = PQgetvalue(res, i, i_amopopr);
12840                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12841                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12842
12843                 if (needComma)
12844                         appendPQExpBufferStr(q, " ,\n    ");
12845
12846                 appendPQExpBuffer(q, "OPERATOR %s %s",
12847                                                   amopstrategy, amopopr);
12848
12849                 if (strlen(sortfamily) > 0)
12850                 {
12851                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12852                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12853                         appendPQExpBufferStr(q, fmtId(sortfamily));
12854                 }
12855
12856                 if (strcmp(amopreqcheck, "t") == 0)
12857                         appendPQExpBufferStr(q, " RECHECK");
12858
12859                 needComma = true;
12860         }
12861
12862         PQclear(res);
12863
12864         /*
12865          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12866          *
12867          * Print only those opfamily members that are tied to the opclass by
12868          * pg_depend entries.
12869          *
12870          * We print the amproclefttype/amprocrighttype even though in most cases
12871          * the backend could deduce the right values, because of the corner case
12872          * of a btree sort support function for a cross-type comparison.  That's
12873          * only allowed in 9.2 and later, but for simplicity print them in all
12874          * versions that have the columns.
12875          */
12876         resetPQExpBuffer(query);
12877
12878         if (fout->remoteVersion >= 80300)
12879         {
12880                 appendPQExpBuffer(query, "SELECT amprocnum, "
12881                                                   "amproc::pg_catalog.regprocedure, "
12882                                                   "amproclefttype::pg_catalog.regtype, "
12883                                                   "amprocrighttype::pg_catalog.regtype "
12884                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12885                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12886                                                   "AND refobjid = '%u'::pg_catalog.oid "
12887                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12888                                                   "AND objid = ap.oid "
12889                                                   "ORDER BY amprocnum",
12890                                                   opcinfo->dobj.catId.oid);
12891         }
12892         else
12893         {
12894                 appendPQExpBuffer(query, "SELECT amprocnum, "
12895                                                   "amproc::pg_catalog.regprocedure, "
12896                                                   "'' AS amproclefttype, "
12897                                                   "'' AS amprocrighttype "
12898                                                   "FROM pg_catalog.pg_amproc "
12899                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12900                                                   "ORDER BY amprocnum",
12901                                                   opcinfo->dobj.catId.oid);
12902         }
12903
12904         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12905
12906         ntups = PQntuples(res);
12907
12908         i_amprocnum = PQfnumber(res, "amprocnum");
12909         i_amproc = PQfnumber(res, "amproc");
12910         i_amproclefttype = PQfnumber(res, "amproclefttype");
12911         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12912
12913         for (i = 0; i < ntups; i++)
12914         {
12915                 amprocnum = PQgetvalue(res, i, i_amprocnum);
12916                 amproc = PQgetvalue(res, i, i_amproc);
12917                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12918                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12919
12920                 if (needComma)
12921                         appendPQExpBufferStr(q, " ,\n    ");
12922
12923                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12924
12925                 if (*amproclefttype && *amprocrighttype)
12926                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12927
12928                 appendPQExpBuffer(q, " %s", amproc);
12929
12930                 needComma = true;
12931         }
12932
12933         PQclear(res);
12934
12935         /*
12936          * If needComma is still false it means we haven't added anything after
12937          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
12938          * clause with the same datatype.  This isn't sanctioned by the
12939          * documentation, but actually DefineOpClass will treat it as a no-op.
12940          */
12941         if (!needComma)
12942                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
12943
12944         appendPQExpBufferStr(q, ";\n");
12945
12946         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
12947         appendPQExpBuffer(nameusing, " USING %s",
12948                                           fmtId(amname));
12949
12950         if (dopt->binary_upgrade)
12951                 binary_upgrade_extension_member(q, &opcinfo->dobj,
12952                                                                                 "OPERATOR CLASS", nameusing->data,
12953                                                                                 opcinfo->dobj.namespace->dobj.name);
12954
12955         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12956                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12957                                          opcinfo->dobj.name,
12958                                          opcinfo->dobj.namespace->dobj.name,
12959                                          NULL,
12960                                          opcinfo->rolname,
12961                                          "OPERATOR CLASS", SECTION_PRE_DATA,
12962                                          q->data, delq->data, NULL,
12963                                          NULL, 0,
12964                                          NULL, NULL);
12965
12966         /* Dump Operator Class Comments */
12967         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12968                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
12969                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
12970                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
12971
12972         free(opcintype);
12973         free(opcfamily);
12974         free(amname);
12975         destroyPQExpBuffer(query);
12976         destroyPQExpBuffer(q);
12977         destroyPQExpBuffer(delq);
12978         destroyPQExpBuffer(nameusing);
12979 }
12980
12981 /*
12982  * dumpOpfamily
12983  *        write out a single operator family definition
12984  *
12985  * Note: this also dumps any "loose" operator members that aren't bound to a
12986  * specific opclass within the opfamily.
12987  */
12988 static void
12989 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
12990 {
12991         DumpOptions *dopt = fout->dopt;
12992         PQExpBuffer query;
12993         PQExpBuffer q;
12994         PQExpBuffer delq;
12995         PQExpBuffer nameusing;
12996         PGresult   *res;
12997         PGresult   *res_ops;
12998         PGresult   *res_procs;
12999         int                     ntups;
13000         int                     i_amname;
13001         int                     i_amopstrategy;
13002         int                     i_amopreqcheck;
13003         int                     i_amopopr;
13004         int                     i_sortfamily;
13005         int                     i_sortfamilynsp;
13006         int                     i_amprocnum;
13007         int                     i_amproc;
13008         int                     i_amproclefttype;
13009         int                     i_amprocrighttype;
13010         char       *amname;
13011         char       *amopstrategy;
13012         char       *amopreqcheck;
13013         char       *amopopr;
13014         char       *sortfamily;
13015         char       *sortfamilynsp;
13016         char       *amprocnum;
13017         char       *amproc;
13018         char       *amproclefttype;
13019         char       *amprocrighttype;
13020         bool            needComma;
13021         int                     i;
13022
13023         /* Skip if not to be dumped */
13024         if (!opfinfo->dobj.dump || dopt->dataOnly)
13025                 return;
13026
13027         query = createPQExpBuffer();
13028         q = createPQExpBuffer();
13029         delq = createPQExpBuffer();
13030         nameusing = createPQExpBuffer();
13031
13032         /*
13033          * Fetch only those opfamily members that are tied directly to the
13034          * opfamily by pg_depend entries.
13035          *
13036          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13037          * older server's opclass in which it is used.  This is to avoid
13038          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13039          * older server and then reload into that old version.  This can go away
13040          * once 8.3 is so old as to not be of interest to anyone.
13041          */
13042         if (fout->remoteVersion >= 90100)
13043         {
13044                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13045                                                   "amopopr::pg_catalog.regoperator, "
13046                                                   "opfname AS sortfamily, "
13047                                                   "nspname AS sortfamilynsp "
13048                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13049                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13050                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13051                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13052                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13053                                                   "AND refobjid = '%u'::pg_catalog.oid "
13054                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13055                                                   "ORDER BY amopstrategy",
13056                                                   opfinfo->dobj.catId.oid,
13057                                                   opfinfo->dobj.catId.oid);
13058         }
13059         else if (fout->remoteVersion >= 80400)
13060         {
13061                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13062                                                   "amopopr::pg_catalog.regoperator, "
13063                                                   "NULL AS sortfamily, "
13064                                                   "NULL AS sortfamilynsp "
13065                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13066                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13067                                                   "AND refobjid = '%u'::pg_catalog.oid "
13068                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13069                                                   "AND objid = ao.oid "
13070                                                   "ORDER BY amopstrategy",
13071                                                   opfinfo->dobj.catId.oid);
13072         }
13073         else
13074         {
13075                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13076                                                   "amopopr::pg_catalog.regoperator, "
13077                                                   "NULL AS sortfamily, "
13078                                                   "NULL AS sortfamilynsp "
13079                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13080                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13081                                                   "AND refobjid = '%u'::pg_catalog.oid "
13082                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13083                                                   "AND objid = ao.oid "
13084                                                   "ORDER BY amopstrategy",
13085                                                   opfinfo->dobj.catId.oid);
13086         }
13087
13088         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13089
13090         resetPQExpBuffer(query);
13091
13092         appendPQExpBuffer(query, "SELECT amprocnum, "
13093                                           "amproc::pg_catalog.regprocedure, "
13094                                           "amproclefttype::pg_catalog.regtype, "
13095                                           "amprocrighttype::pg_catalog.regtype "
13096                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13097                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13098                                           "AND refobjid = '%u'::pg_catalog.oid "
13099                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13100                                           "AND objid = ap.oid "
13101                                           "ORDER BY amprocnum",
13102                                           opfinfo->dobj.catId.oid);
13103
13104         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13105
13106         /* Get additional fields from the pg_opfamily row */
13107         resetPQExpBuffer(query);
13108
13109         appendPQExpBuffer(query, "SELECT "
13110                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13111                                           "FROM pg_catalog.pg_opfamily "
13112                                           "WHERE oid = '%u'::pg_catalog.oid",
13113                                           opfinfo->dobj.catId.oid);
13114
13115         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13116
13117         i_amname = PQfnumber(res, "amname");
13118
13119         /* amname will still be needed after we PQclear res */
13120         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13121
13122         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13123                                           fmtQualifiedDumpable(opfinfo));
13124         appendPQExpBuffer(delq, " USING %s;\n",
13125                                           fmtId(amname));
13126
13127         /* Build the fixed portion of the CREATE command */
13128         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13129                                           fmtQualifiedDumpable(opfinfo));
13130         appendPQExpBuffer(q, " USING %s;\n",
13131                                           fmtId(amname));
13132
13133         PQclear(res);
13134
13135         /* Do we need an ALTER to add loose members? */
13136         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13137         {
13138                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13139                                                   fmtQualifiedDumpable(opfinfo));
13140                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13141                                                   fmtId(amname));
13142
13143                 needComma = false;
13144
13145                 /*
13146                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13147                  */
13148                 ntups = PQntuples(res_ops);
13149
13150                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13151                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13152                 i_amopopr = PQfnumber(res_ops, "amopopr");
13153                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13154                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13155
13156                 for (i = 0; i < ntups; i++)
13157                 {
13158                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13159                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13160                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13161                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13162                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13163
13164                         if (needComma)
13165                                 appendPQExpBufferStr(q, " ,\n    ");
13166
13167                         appendPQExpBuffer(q, "OPERATOR %s %s",
13168                                                           amopstrategy, amopopr);
13169
13170                         if (strlen(sortfamily) > 0)
13171                         {
13172                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13173                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13174                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13175                         }
13176
13177                         if (strcmp(amopreqcheck, "t") == 0)
13178                                 appendPQExpBufferStr(q, " RECHECK");
13179
13180                         needComma = true;
13181                 }
13182
13183                 /*
13184                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13185                  */
13186                 ntups = PQntuples(res_procs);
13187
13188                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13189                 i_amproc = PQfnumber(res_procs, "amproc");
13190                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13191                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13192
13193                 for (i = 0; i < ntups; i++)
13194                 {
13195                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13196                         amproc = PQgetvalue(res_procs, i, i_amproc);
13197                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13198                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13199
13200                         if (needComma)
13201                                 appendPQExpBufferStr(q, " ,\n    ");
13202
13203                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13204                                                           amprocnum, amproclefttype, amprocrighttype,
13205                                                           amproc);
13206
13207                         needComma = true;
13208                 }
13209
13210                 appendPQExpBufferStr(q, ";\n");
13211         }
13212
13213         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13214         appendPQExpBuffer(nameusing, " USING %s",
13215                                           fmtId(amname));
13216
13217         if (dopt->binary_upgrade)
13218                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13219                                                                                 "OPERATOR FAMILY", nameusing->data,
13220                                                                                 opfinfo->dobj.namespace->dobj.name);
13221
13222         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13223                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13224                                          opfinfo->dobj.name,
13225                                          opfinfo->dobj.namespace->dobj.name,
13226                                          NULL,
13227                                          opfinfo->rolname,
13228                                          "OPERATOR FAMILY", SECTION_PRE_DATA,
13229                                          q->data, delq->data, NULL,
13230                                          NULL, 0,
13231                                          NULL, NULL);
13232
13233         /* Dump Operator Family Comments */
13234         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13235                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13236                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13237                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13238
13239         free(amname);
13240         PQclear(res_ops);
13241         PQclear(res_procs);
13242         destroyPQExpBuffer(query);
13243         destroyPQExpBuffer(q);
13244         destroyPQExpBuffer(delq);
13245         destroyPQExpBuffer(nameusing);
13246 }
13247
13248 /*
13249  * dumpCollation
13250  *        write out a single collation definition
13251  */
13252 static void
13253 dumpCollation(Archive *fout, CollInfo *collinfo)
13254 {
13255         DumpOptions *dopt = fout->dopt;
13256         PQExpBuffer query;
13257         PQExpBuffer q;
13258         PQExpBuffer delq;
13259         char       *qcollname;
13260         PGresult   *res;
13261         int                     i_collprovider;
13262         int                     i_collcollate;
13263         int                     i_collctype;
13264         const char *collprovider;
13265         const char *collcollate;
13266         const char *collctype;
13267
13268         /* Skip if not to be dumped */
13269         if (!collinfo->dobj.dump || dopt->dataOnly)
13270                 return;
13271
13272         query = createPQExpBuffer();
13273         q = createPQExpBuffer();
13274         delq = createPQExpBuffer();
13275
13276         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13277
13278         /* Get collation-specific details */
13279         if (fout->remoteVersion >= 100000)
13280                 appendPQExpBuffer(query, "SELECT "
13281                                                   "collprovider, "
13282                                                   "collcollate, "
13283                                                   "collctype, "
13284                                                   "collversion "
13285                                                   "FROM pg_catalog.pg_collation c "
13286                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13287                                                   collinfo->dobj.catId.oid);
13288         else
13289                 appendPQExpBuffer(query, "SELECT "
13290                                                   "'c' AS collprovider, "
13291                                                   "collcollate, "
13292                                                   "collctype, "
13293                                                   "NULL AS collversion "
13294                                                   "FROM pg_catalog.pg_collation c "
13295                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13296                                                   collinfo->dobj.catId.oid);
13297
13298         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13299
13300         i_collprovider = PQfnumber(res, "collprovider");
13301         i_collcollate = PQfnumber(res, "collcollate");
13302         i_collctype = PQfnumber(res, "collctype");
13303
13304         collprovider = PQgetvalue(res, 0, i_collprovider);
13305         collcollate = PQgetvalue(res, 0, i_collcollate);
13306         collctype = PQgetvalue(res, 0, i_collctype);
13307
13308         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13309                                           fmtQualifiedDumpable(collinfo));
13310
13311         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13312                                           fmtQualifiedDumpable(collinfo));
13313
13314         appendPQExpBufferStr(q, "provider = ");
13315         if (collprovider[0] == 'c')
13316                 appendPQExpBufferStr(q, "libc");
13317         else if (collprovider[0] == 'i')
13318                 appendPQExpBufferStr(q, "icu");
13319         else if (collprovider[0] == 'd')
13320                 /* to allow dumping pg_catalog; not accepted on input */
13321                 appendPQExpBufferStr(q, "default");
13322         else
13323                 exit_horribly(NULL,
13324                                           "unrecognized collation provider: %s\n",
13325                                           collprovider);
13326
13327         if (strcmp(collcollate, collctype) == 0)
13328         {
13329                 appendPQExpBufferStr(q, ", locale = ");
13330                 appendStringLiteralAH(q, collcollate, fout);
13331         }
13332         else
13333         {
13334                 appendPQExpBufferStr(q, ", lc_collate = ");
13335                 appendStringLiteralAH(q, collcollate, fout);
13336                 appendPQExpBufferStr(q, ", lc_ctype = ");
13337                 appendStringLiteralAH(q, collctype, fout);
13338         }
13339
13340         /*
13341          * For binary upgrade, carry over the collation version.  For normal
13342          * dump/restore, omit the version, so that it is computed upon restore.
13343          */
13344         if (dopt->binary_upgrade)
13345         {
13346                 int                     i_collversion;
13347
13348                 i_collversion = PQfnumber(res, "collversion");
13349                 if (!PQgetisnull(res, 0, i_collversion))
13350                 {
13351                         appendPQExpBufferStr(q, ", version = ");
13352                         appendStringLiteralAH(q,
13353                                                                   PQgetvalue(res, 0, i_collversion),
13354                                                                   fout);
13355                 }
13356         }
13357
13358         appendPQExpBufferStr(q, ");\n");
13359
13360         if (dopt->binary_upgrade)
13361                 binary_upgrade_extension_member(q, &collinfo->dobj,
13362                                                                                 "COLLATION", qcollname,
13363                                                                                 collinfo->dobj.namespace->dobj.name);
13364
13365         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13366                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13367                                          collinfo->dobj.name,
13368                                          collinfo->dobj.namespace->dobj.name,
13369                                          NULL,
13370                                          collinfo->rolname,
13371                                          "COLLATION", SECTION_PRE_DATA,
13372                                          q->data, delq->data, NULL,
13373                                          NULL, 0,
13374                                          NULL, NULL);
13375
13376         /* Dump Collation Comments */
13377         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13378                 dumpComment(fout, "COLLATION", qcollname,
13379                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13380                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13381
13382         PQclear(res);
13383
13384         destroyPQExpBuffer(query);
13385         destroyPQExpBuffer(q);
13386         destroyPQExpBuffer(delq);
13387         free(qcollname);
13388 }
13389
13390 /*
13391  * dumpConversion
13392  *        write out a single conversion definition
13393  */
13394 static void
13395 dumpConversion(Archive *fout, ConvInfo *convinfo)
13396 {
13397         DumpOptions *dopt = fout->dopt;
13398         PQExpBuffer query;
13399         PQExpBuffer q;
13400         PQExpBuffer delq;
13401         char       *qconvname;
13402         PGresult   *res;
13403         int                     i_conforencoding;
13404         int                     i_contoencoding;
13405         int                     i_conproc;
13406         int                     i_condefault;
13407         const char *conforencoding;
13408         const char *contoencoding;
13409         const char *conproc;
13410         bool            condefault;
13411
13412         /* Skip if not to be dumped */
13413         if (!convinfo->dobj.dump || dopt->dataOnly)
13414                 return;
13415
13416         query = createPQExpBuffer();
13417         q = createPQExpBuffer();
13418         delq = createPQExpBuffer();
13419
13420         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13421
13422         /* Get conversion-specific details */
13423         appendPQExpBuffer(query, "SELECT "
13424                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13425                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13426                                           "conproc, condefault "
13427                                           "FROM pg_catalog.pg_conversion c "
13428                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13429                                           convinfo->dobj.catId.oid);
13430
13431         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13432
13433         i_conforencoding = PQfnumber(res, "conforencoding");
13434         i_contoencoding = PQfnumber(res, "contoencoding");
13435         i_conproc = PQfnumber(res, "conproc");
13436         i_condefault = PQfnumber(res, "condefault");
13437
13438         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13439         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13440         conproc = PQgetvalue(res, 0, i_conproc);
13441         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13442
13443         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13444                                           fmtQualifiedDumpable(convinfo));
13445
13446         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13447                                           (condefault) ? "DEFAULT " : "",
13448                                           fmtQualifiedDumpable(convinfo));
13449         appendStringLiteralAH(q, conforencoding, fout);
13450         appendPQExpBufferStr(q, " TO ");
13451         appendStringLiteralAH(q, contoencoding, fout);
13452         /* regproc output is already sufficiently quoted */
13453         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13454
13455         if (dopt->binary_upgrade)
13456                 binary_upgrade_extension_member(q, &convinfo->dobj,
13457                                                                                 "CONVERSION", qconvname,
13458                                                                                 convinfo->dobj.namespace->dobj.name);
13459
13460         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13461                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13462                                          convinfo->dobj.name,
13463                                          convinfo->dobj.namespace->dobj.name,
13464                                          NULL,
13465                                          convinfo->rolname,
13466                                          "CONVERSION", SECTION_PRE_DATA,
13467                                          q->data, delq->data, NULL,
13468                                          NULL, 0,
13469                                          NULL, NULL);
13470
13471         /* Dump Conversion Comments */
13472         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13473                 dumpComment(fout, "CONVERSION", qconvname,
13474                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13475                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13476
13477         PQclear(res);
13478
13479         destroyPQExpBuffer(query);
13480         destroyPQExpBuffer(q);
13481         destroyPQExpBuffer(delq);
13482         free(qconvname);
13483 }
13484
13485 /*
13486  * format_aggregate_signature: generate aggregate name and argument list
13487  *
13488  * The argument type names are qualified if needed.  The aggregate name
13489  * is never qualified.
13490  */
13491 static char *
13492 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13493 {
13494         PQExpBufferData buf;
13495         int                     j;
13496
13497         initPQExpBuffer(&buf);
13498         if (honor_quotes)
13499                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13500         else
13501                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13502
13503         if (agginfo->aggfn.nargs == 0)
13504                 appendPQExpBuffer(&buf, "(*)");
13505         else
13506         {
13507                 appendPQExpBufferChar(&buf, '(');
13508                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13509                 {
13510                         char       *typname;
13511
13512                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13513                                                                                    zeroAsOpaque);
13514
13515                         appendPQExpBuffer(&buf, "%s%s",
13516                                                           (j > 0) ? ", " : "",
13517                                                           typname);
13518                         free(typname);
13519                 }
13520                 appendPQExpBufferChar(&buf, ')');
13521         }
13522         return buf.data;
13523 }
13524
13525 /*
13526  * dumpAgg
13527  *        write out a single aggregate definition
13528  */
13529 static void
13530 dumpAgg(Archive *fout, AggInfo *agginfo)
13531 {
13532         DumpOptions *dopt = fout->dopt;
13533         PQExpBuffer query;
13534         PQExpBuffer q;
13535         PQExpBuffer delq;
13536         PQExpBuffer details;
13537         char       *aggsig;                     /* identity signature */
13538         char       *aggfullsig = NULL;  /* full signature */
13539         char       *aggsig_tag;
13540         PGresult   *res;
13541         int                     i_aggtransfn;
13542         int                     i_aggfinalfn;
13543         int                     i_aggcombinefn;
13544         int                     i_aggserialfn;
13545         int                     i_aggdeserialfn;
13546         int                     i_aggmtransfn;
13547         int                     i_aggminvtransfn;
13548         int                     i_aggmfinalfn;
13549         int                     i_aggfinalextra;
13550         int                     i_aggmfinalextra;
13551         int                     i_aggfinalmodify;
13552         int                     i_aggmfinalmodify;
13553         int                     i_aggsortop;
13554         int                     i_aggkind;
13555         int                     i_aggtranstype;
13556         int                     i_aggtransspace;
13557         int                     i_aggmtranstype;
13558         int                     i_aggmtransspace;
13559         int                     i_agginitval;
13560         int                     i_aggminitval;
13561         int                     i_convertok;
13562         int                     i_proparallel;
13563         const char *aggtransfn;
13564         const char *aggfinalfn;
13565         const char *aggcombinefn;
13566         const char *aggserialfn;
13567         const char *aggdeserialfn;
13568         const char *aggmtransfn;
13569         const char *aggminvtransfn;
13570         const char *aggmfinalfn;
13571         bool            aggfinalextra;
13572         bool            aggmfinalextra;
13573         char            aggfinalmodify;
13574         char            aggmfinalmodify;
13575         const char *aggsortop;
13576         char       *aggsortconvop;
13577         char            aggkind;
13578         const char *aggtranstype;
13579         const char *aggtransspace;
13580         const char *aggmtranstype;
13581         const char *aggmtransspace;
13582         const char *agginitval;
13583         const char *aggminitval;
13584         bool            convertok;
13585         const char *proparallel;
13586         char            defaultfinalmodify;
13587
13588         /* Skip if not to be dumped */
13589         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13590                 return;
13591
13592         query = createPQExpBuffer();
13593         q = createPQExpBuffer();
13594         delq = createPQExpBuffer();
13595         details = createPQExpBuffer();
13596
13597         /* Get aggregate-specific details */
13598         if (fout->remoteVersion >= 110000)
13599         {
13600                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13601                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13602                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13603                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13604                                                   "aggfinalextra, aggmfinalextra, "
13605                                                   "aggfinalmodify, aggmfinalmodify, "
13606                                                   "aggsortop, "
13607                                                   "aggkind, "
13608                                                   "aggtransspace, agginitval, "
13609                                                   "aggmtransspace, aggminitval, "
13610                                                   "true AS convertok, "
13611                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13612                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13613                                                   "p.proparallel "
13614                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13615                                                   "WHERE a.aggfnoid = p.oid "
13616                                                   "AND p.oid = '%u'::pg_catalog.oid",
13617                                                   agginfo->aggfn.dobj.catId.oid);
13618         }
13619         else if (fout->remoteVersion >= 90600)
13620         {
13621                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13622                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13623                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13624                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13625                                                   "aggfinalextra, aggmfinalextra, "
13626                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13627                                                   "aggsortop, "
13628                                                   "aggkind, "
13629                                                   "aggtransspace, agginitval, "
13630                                                   "aggmtransspace, aggminitval, "
13631                                                   "true AS convertok, "
13632                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13633                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13634                                                   "p.proparallel "
13635                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13636                                                   "WHERE a.aggfnoid = p.oid "
13637                                                   "AND p.oid = '%u'::pg_catalog.oid",
13638                                                   agginfo->aggfn.dobj.catId.oid);
13639         }
13640         else if (fout->remoteVersion >= 90400)
13641         {
13642                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13643                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13644                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13645                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13646                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13647                                                   "aggfinalextra, aggmfinalextra, "
13648                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13649                                                   "aggsortop, "
13650                                                   "aggkind, "
13651                                                   "aggtransspace, agginitval, "
13652                                                   "aggmtransspace, aggminitval, "
13653                                                   "true AS convertok, "
13654                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13655                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13656                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13657                                                   "WHERE a.aggfnoid = p.oid "
13658                                                   "AND p.oid = '%u'::pg_catalog.oid",
13659                                                   agginfo->aggfn.dobj.catId.oid);
13660         }
13661         else if (fout->remoteVersion >= 80400)
13662         {
13663                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13664                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13665                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13666                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13667                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13668                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13669                                                   "false AS aggmfinalextra, "
13670                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13671                                                   "aggsortop, "
13672                                                   "'n' AS aggkind, "
13673                                                   "0 AS aggtransspace, agginitval, "
13674                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13675                                                   "true AS convertok, "
13676                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13677                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13678                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13679                                                   "WHERE a.aggfnoid = p.oid "
13680                                                   "AND p.oid = '%u'::pg_catalog.oid",
13681                                                   agginfo->aggfn.dobj.catId.oid);
13682         }
13683         else if (fout->remoteVersion >= 80100)
13684         {
13685                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13686                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13687                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13688                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13689                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13690                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13691                                                   "false AS aggmfinalextra, "
13692                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13693                                                   "aggsortop, "
13694                                                   "'n' AS aggkind, "
13695                                                   "0 AS aggtransspace, agginitval, "
13696                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13697                                                   "true AS convertok "
13698                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13699                                                   "WHERE a.aggfnoid = p.oid "
13700                                                   "AND p.oid = '%u'::pg_catalog.oid",
13701                                                   agginfo->aggfn.dobj.catId.oid);
13702         }
13703         else
13704         {
13705                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13706                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13707                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13708                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13709                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13710                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13711                                                   "false AS aggmfinalextra, "
13712                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13713                                                   "0 AS aggsortop, "
13714                                                   "'n' AS aggkind, "
13715                                                   "0 AS aggtransspace, agginitval, "
13716                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13717                                                   "true AS convertok "
13718                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13719                                                   "WHERE a.aggfnoid = p.oid "
13720                                                   "AND p.oid = '%u'::pg_catalog.oid",
13721                                                   agginfo->aggfn.dobj.catId.oid);
13722         }
13723
13724         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13725
13726         i_aggtransfn = PQfnumber(res, "aggtransfn");
13727         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13728         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13729         i_aggserialfn = PQfnumber(res, "aggserialfn");
13730         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13731         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13732         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13733         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13734         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13735         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13736         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13737         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13738         i_aggsortop = PQfnumber(res, "aggsortop");
13739         i_aggkind = PQfnumber(res, "aggkind");
13740         i_aggtranstype = PQfnumber(res, "aggtranstype");
13741         i_aggtransspace = PQfnumber(res, "aggtransspace");
13742         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13743         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13744         i_agginitval = PQfnumber(res, "agginitval");
13745         i_aggminitval = PQfnumber(res, "aggminitval");
13746         i_convertok = PQfnumber(res, "convertok");
13747         i_proparallel = PQfnumber(res, "proparallel");
13748
13749         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13750         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13751         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13752         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13753         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13754         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13755         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13756         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13757         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13758         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13759         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13760         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13761         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13762         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13763         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13764         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13765         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13766         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13767         agginitval = PQgetvalue(res, 0, i_agginitval);
13768         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13769         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13770
13771         if (fout->remoteVersion >= 80400)
13772         {
13773                 /* 8.4 or later; we rely on server-side code for most of the work */
13774                 char       *funcargs;
13775                 char       *funciargs;
13776
13777                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13778                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13779                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13780                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13781         }
13782         else
13783                 /* pre-8.4, do it ourselves */
13784                 aggsig = format_aggregate_signature(agginfo, fout, true);
13785
13786         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13787
13788         if (i_proparallel != -1)
13789                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13790         else
13791                 proparallel = NULL;
13792
13793         if (!convertok)
13794         {
13795                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13796                                   aggsig);
13797
13798                 if (aggfullsig)
13799                         free(aggfullsig);
13800
13801                 free(aggsig);
13802
13803                 return;
13804         }
13805
13806         /* identify default modify flag for aggkind (must match DefineAggregate) */
13807         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13808         /* replace omitted flags for old versions */
13809         if (aggfinalmodify == '0')
13810                 aggfinalmodify = defaultfinalmodify;
13811         if (aggmfinalmodify == '0')
13812                 aggmfinalmodify = defaultfinalmodify;
13813
13814         /* regproc and regtype output is already sufficiently quoted */
13815         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13816                                           aggtransfn, aggtranstype);
13817
13818         if (strcmp(aggtransspace, "0") != 0)
13819         {
13820                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13821                                                   aggtransspace);
13822         }
13823
13824         if (!PQgetisnull(res, 0, i_agginitval))
13825         {
13826                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13827                 appendStringLiteralAH(details, agginitval, fout);
13828         }
13829
13830         if (strcmp(aggfinalfn, "-") != 0)
13831         {
13832                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13833                                                   aggfinalfn);
13834                 if (aggfinalextra)
13835                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13836                 if (aggfinalmodify != defaultfinalmodify)
13837                 {
13838                         switch (aggfinalmodify)
13839                         {
13840                                 case AGGMODIFY_READ_ONLY:
13841                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13842                                         break;
13843                                 case AGGMODIFY_SHAREABLE:
13844                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
13845                                         break;
13846                                 case AGGMODIFY_READ_WRITE:
13847                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13848                                         break;
13849                                 default:
13850                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
13851                                                                   agginfo->aggfn.dobj.name);
13852                                         break;
13853                         }
13854                 }
13855         }
13856
13857         if (strcmp(aggcombinefn, "-") != 0)
13858                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13859
13860         if (strcmp(aggserialfn, "-") != 0)
13861                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13862
13863         if (strcmp(aggdeserialfn, "-") != 0)
13864                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13865
13866         if (strcmp(aggmtransfn, "-") != 0)
13867         {
13868                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13869                                                   aggmtransfn,
13870                                                   aggminvtransfn,
13871                                                   aggmtranstype);
13872         }
13873
13874         if (strcmp(aggmtransspace, "0") != 0)
13875         {
13876                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
13877                                                   aggmtransspace);
13878         }
13879
13880         if (!PQgetisnull(res, 0, i_aggminitval))
13881         {
13882                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
13883                 appendStringLiteralAH(details, aggminitval, fout);
13884         }
13885
13886         if (strcmp(aggmfinalfn, "-") != 0)
13887         {
13888                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
13889                                                   aggmfinalfn);
13890                 if (aggmfinalextra)
13891                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
13892                 if (aggmfinalmodify != defaultfinalmodify)
13893                 {
13894                         switch (aggmfinalmodify)
13895                         {
13896                                 case AGGMODIFY_READ_ONLY:
13897                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
13898                                         break;
13899                                 case AGGMODIFY_SHAREABLE:
13900                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
13901                                         break;
13902                                 case AGGMODIFY_READ_WRITE:
13903                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
13904                                         break;
13905                                 default:
13906                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
13907                                                                   agginfo->aggfn.dobj.name);
13908                                         break;
13909                         }
13910                 }
13911         }
13912
13913         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
13914         if (aggsortconvop)
13915         {
13916                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
13917                                                   aggsortconvop);
13918                 free(aggsortconvop);
13919         }
13920
13921         if (aggkind == AGGKIND_HYPOTHETICAL)
13922                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
13923
13924         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13925         {
13926                 if (proparallel[0] == PROPARALLEL_SAFE)
13927                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
13928                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13929                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
13930                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13931                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13932                                                   agginfo->aggfn.dobj.name);
13933         }
13934
13935         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13936                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13937                                           aggsig);
13938
13939         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
13940                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13941                                           aggfullsig ? aggfullsig : aggsig, details->data);
13942
13943         if (dopt->binary_upgrade)
13944                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
13945                                                                                 "AGGREGATE", aggsig,
13946                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
13947
13948         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13949                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13950                                          agginfo->aggfn.dobj.dumpId,
13951                                          aggsig_tag,
13952                                          agginfo->aggfn.dobj.namespace->dobj.name,
13953                                          NULL,
13954                                          agginfo->aggfn.rolname,
13955                                          "AGGREGATE", SECTION_PRE_DATA,
13956                                          q->data, delq->data, NULL,
13957                                          NULL, 0,
13958                                          NULL, NULL);
13959
13960         /* Dump Aggregate Comments */
13961         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13962                 dumpComment(fout, "AGGREGATE", aggsig,
13963                                         agginfo->aggfn.dobj.namespace->dobj.name,
13964                                         agginfo->aggfn.rolname,
13965                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13966
13967         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
13968                 dumpSecLabel(fout, "AGGREGATE", aggsig,
13969                                          agginfo->aggfn.dobj.namespace->dobj.name,
13970                                          agginfo->aggfn.rolname,
13971                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13972
13973         /*
13974          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
13975          * command look like a function's GRANT; in particular this affects the
13976          * syntax for zero-argument aggregates and ordered-set aggregates.
13977          */
13978         free(aggsig);
13979
13980         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
13981
13982         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
13983                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
13984                                 "FUNCTION", aggsig, NULL,
13985                                 agginfo->aggfn.dobj.namespace->dobj.name,
13986                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
13987                                 agginfo->aggfn.rproacl,
13988                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
13989
13990         free(aggsig);
13991         if (aggfullsig)
13992                 free(aggfullsig);
13993         free(aggsig_tag);
13994
13995         PQclear(res);
13996
13997         destroyPQExpBuffer(query);
13998         destroyPQExpBuffer(q);
13999         destroyPQExpBuffer(delq);
14000         destroyPQExpBuffer(details);
14001 }
14002
14003 /*
14004  * dumpTSParser
14005  *        write out a single text search parser
14006  */
14007 static void
14008 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14009 {
14010         DumpOptions *dopt = fout->dopt;
14011         PQExpBuffer q;
14012         PQExpBuffer delq;
14013         char       *qprsname;
14014
14015         /* Skip if not to be dumped */
14016         if (!prsinfo->dobj.dump || dopt->dataOnly)
14017                 return;
14018
14019         q = createPQExpBuffer();
14020         delq = createPQExpBuffer();
14021
14022         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14023
14024         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14025                                           fmtQualifiedDumpable(prsinfo));
14026
14027         appendPQExpBuffer(q, "    START = %s,\n",
14028                                           convertTSFunction(fout, prsinfo->prsstart));
14029         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14030                                           convertTSFunction(fout, prsinfo->prstoken));
14031         appendPQExpBuffer(q, "    END = %s,\n",
14032                                           convertTSFunction(fout, prsinfo->prsend));
14033         if (prsinfo->prsheadline != InvalidOid)
14034                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14035                                                   convertTSFunction(fout, prsinfo->prsheadline));
14036         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14037                                           convertTSFunction(fout, prsinfo->prslextype));
14038
14039         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14040                                           fmtQualifiedDumpable(prsinfo));
14041
14042         if (dopt->binary_upgrade)
14043                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14044                                                                                 "TEXT SEARCH PARSER", qprsname,
14045                                                                                 prsinfo->dobj.namespace->dobj.name);
14046
14047         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14048                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14049                                          prsinfo->dobj.name,
14050                                          prsinfo->dobj.namespace->dobj.name,
14051                                          NULL,
14052                                          "",
14053                                          "TEXT SEARCH PARSER", SECTION_PRE_DATA,
14054                                          q->data, delq->data, NULL,
14055                                          NULL, 0,
14056                                          NULL, NULL);
14057
14058         /* Dump Parser Comments */
14059         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14060                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14061                                         prsinfo->dobj.namespace->dobj.name, "",
14062                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14063
14064         destroyPQExpBuffer(q);
14065         destroyPQExpBuffer(delq);
14066         free(qprsname);
14067 }
14068
14069 /*
14070  * dumpTSDictionary
14071  *        write out a single text search dictionary
14072  */
14073 static void
14074 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14075 {
14076         DumpOptions *dopt = fout->dopt;
14077         PQExpBuffer q;
14078         PQExpBuffer delq;
14079         PQExpBuffer query;
14080         char       *qdictname;
14081         PGresult   *res;
14082         char       *nspname;
14083         char       *tmplname;
14084
14085         /* Skip if not to be dumped */
14086         if (!dictinfo->dobj.dump || dopt->dataOnly)
14087                 return;
14088
14089         q = createPQExpBuffer();
14090         delq = createPQExpBuffer();
14091         query = createPQExpBuffer();
14092
14093         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14094
14095         /* Fetch name and namespace of the dictionary's template */
14096         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14097                                           "FROM pg_ts_template p, pg_namespace n "
14098                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14099                                           dictinfo->dicttemplate);
14100         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14101         nspname = PQgetvalue(res, 0, 0);
14102         tmplname = PQgetvalue(res, 0, 1);
14103
14104         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14105                                           fmtQualifiedDumpable(dictinfo));
14106
14107         appendPQExpBufferStr(q, "    TEMPLATE = ");
14108         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14109         appendPQExpBufferStr(q, fmtId(tmplname));
14110
14111         PQclear(res);
14112
14113         /* the dictinitoption can be dumped straight into the command */
14114         if (dictinfo->dictinitoption)
14115                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14116
14117         appendPQExpBufferStr(q, " );\n");
14118
14119         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14120                                           fmtQualifiedDumpable(dictinfo));
14121
14122         if (dopt->binary_upgrade)
14123                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14124                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14125                                                                                 dictinfo->dobj.namespace->dobj.name);
14126
14127         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14128                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14129                                          dictinfo->dobj.name,
14130                                          dictinfo->dobj.namespace->dobj.name,
14131                                          NULL,
14132                                          dictinfo->rolname,
14133                                          "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
14134                                          q->data, delq->data, NULL,
14135                                          NULL, 0,
14136                                          NULL, NULL);
14137
14138         /* Dump Dictionary Comments */
14139         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14140                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14141                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14142                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14143
14144         destroyPQExpBuffer(q);
14145         destroyPQExpBuffer(delq);
14146         destroyPQExpBuffer(query);
14147         free(qdictname);
14148 }
14149
14150 /*
14151  * dumpTSTemplate
14152  *        write out a single text search template
14153  */
14154 static void
14155 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14156 {
14157         DumpOptions *dopt = fout->dopt;
14158         PQExpBuffer q;
14159         PQExpBuffer delq;
14160         char       *qtmplname;
14161
14162         /* Skip if not to be dumped */
14163         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14164                 return;
14165
14166         q = createPQExpBuffer();
14167         delq = createPQExpBuffer();
14168
14169         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14170
14171         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14172                                           fmtQualifiedDumpable(tmplinfo));
14173
14174         if (tmplinfo->tmplinit != InvalidOid)
14175                 appendPQExpBuffer(q, "    INIT = %s,\n",
14176                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14177         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14178                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14179
14180         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14181                                           fmtQualifiedDumpable(tmplinfo));
14182
14183         if (dopt->binary_upgrade)
14184                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14185                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14186                                                                                 tmplinfo->dobj.namespace->dobj.name);
14187
14188         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14189                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14190                                          tmplinfo->dobj.name,
14191                                          tmplinfo->dobj.namespace->dobj.name,
14192                                          NULL,
14193                                          "",
14194                                          "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
14195                                          q->data, delq->data, NULL,
14196                                          NULL, 0,
14197                                          NULL, NULL);
14198
14199         /* Dump Template Comments */
14200         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14201                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14202                                         tmplinfo->dobj.namespace->dobj.name, "",
14203                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14204
14205         destroyPQExpBuffer(q);
14206         destroyPQExpBuffer(delq);
14207         free(qtmplname);
14208 }
14209
14210 /*
14211  * dumpTSConfig
14212  *        write out a single text search configuration
14213  */
14214 static void
14215 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14216 {
14217         DumpOptions *dopt = fout->dopt;
14218         PQExpBuffer q;
14219         PQExpBuffer delq;
14220         PQExpBuffer query;
14221         char       *qcfgname;
14222         PGresult   *res;
14223         char       *nspname;
14224         char       *prsname;
14225         int                     ntups,
14226                                 i;
14227         int                     i_tokenname;
14228         int                     i_dictname;
14229
14230         /* Skip if not to be dumped */
14231         if (!cfginfo->dobj.dump || dopt->dataOnly)
14232                 return;
14233
14234         q = createPQExpBuffer();
14235         delq = createPQExpBuffer();
14236         query = createPQExpBuffer();
14237
14238         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14239
14240         /* Fetch name and namespace of the config's parser */
14241         appendPQExpBuffer(query, "SELECT nspname, prsname "
14242                                           "FROM pg_ts_parser p, pg_namespace n "
14243                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14244                                           cfginfo->cfgparser);
14245         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14246         nspname = PQgetvalue(res, 0, 0);
14247         prsname = PQgetvalue(res, 0, 1);
14248
14249         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14250                                           fmtQualifiedDumpable(cfginfo));
14251
14252         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14253         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14254
14255         PQclear(res);
14256
14257         resetPQExpBuffer(query);
14258         appendPQExpBuffer(query,
14259                                           "SELECT\n"
14260                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14261                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14262                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14263                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14264                                           "WHERE m.mapcfg = '%u'\n"
14265                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14266                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14267
14268         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14269         ntups = PQntuples(res);
14270
14271         i_tokenname = PQfnumber(res, "tokenname");
14272         i_dictname = PQfnumber(res, "dictname");
14273
14274         for (i = 0; i < ntups; i++)
14275         {
14276                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14277                 char       *dictname = PQgetvalue(res, i, i_dictname);
14278
14279                 if (i == 0 ||
14280                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14281                 {
14282                         /* starting a new token type, so start a new command */
14283                         if (i > 0)
14284                                 appendPQExpBufferStr(q, ";\n");
14285                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14286                                                           fmtQualifiedDumpable(cfginfo));
14287                         /* tokenname needs quoting, dictname does NOT */
14288                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14289                                                           fmtId(tokenname), dictname);
14290                 }
14291                 else
14292                         appendPQExpBuffer(q, ", %s", dictname);
14293         }
14294
14295         if (ntups > 0)
14296                 appendPQExpBufferStr(q, ";\n");
14297
14298         PQclear(res);
14299
14300         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14301                                           fmtQualifiedDumpable(cfginfo));
14302
14303         if (dopt->binary_upgrade)
14304                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14305                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14306                                                                                 cfginfo->dobj.namespace->dobj.name);
14307
14308         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14309                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14310                                          cfginfo->dobj.name,
14311                                          cfginfo->dobj.namespace->dobj.name,
14312                                          NULL,
14313                                          cfginfo->rolname,
14314                                          "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14315                                          q->data, delq->data, NULL,
14316                                          NULL, 0,
14317                                          NULL, NULL);
14318
14319         /* Dump Configuration Comments */
14320         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14321                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14322                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14323                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14324
14325         destroyPQExpBuffer(q);
14326         destroyPQExpBuffer(delq);
14327         destroyPQExpBuffer(query);
14328         free(qcfgname);
14329 }
14330
14331 /*
14332  * dumpForeignDataWrapper
14333  *        write out a single foreign-data wrapper definition
14334  */
14335 static void
14336 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14337 {
14338         DumpOptions *dopt = fout->dopt;
14339         PQExpBuffer q;
14340         PQExpBuffer delq;
14341         char       *qfdwname;
14342
14343         /* Skip if not to be dumped */
14344         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14345                 return;
14346
14347         q = createPQExpBuffer();
14348         delq = createPQExpBuffer();
14349
14350         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14351
14352         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14353                                           qfdwname);
14354
14355         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14356                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14357
14358         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14359                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14360
14361         if (strlen(fdwinfo->fdwoptions) > 0)
14362                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14363
14364         appendPQExpBufferStr(q, ";\n");
14365
14366         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14367                                           qfdwname);
14368
14369         if (dopt->binary_upgrade)
14370                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14371                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14372                                                                                 NULL);
14373
14374         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14375                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14376                                          fdwinfo->dobj.name,
14377                                          NULL,
14378                                          NULL,
14379                                          fdwinfo->rolname,
14380                                          "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14381                                          q->data, delq->data, NULL,
14382                                          NULL, 0,
14383                                          NULL, NULL);
14384
14385         /* Dump Foreign Data Wrapper Comments */
14386         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14387                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14388                                         NULL, fdwinfo->rolname,
14389                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14390
14391         /* Handle the ACL */
14392         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14393                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14394                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14395                                 NULL, fdwinfo->rolname,
14396                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14397                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14398
14399         free(qfdwname);
14400
14401         destroyPQExpBuffer(q);
14402         destroyPQExpBuffer(delq);
14403 }
14404
14405 /*
14406  * dumpForeignServer
14407  *        write out a foreign server definition
14408  */
14409 static void
14410 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14411 {
14412         DumpOptions *dopt = fout->dopt;
14413         PQExpBuffer q;
14414         PQExpBuffer delq;
14415         PQExpBuffer query;
14416         PGresult   *res;
14417         char       *qsrvname;
14418         char       *fdwname;
14419
14420         /* Skip if not to be dumped */
14421         if (!srvinfo->dobj.dump || dopt->dataOnly)
14422                 return;
14423
14424         q = createPQExpBuffer();
14425         delq = createPQExpBuffer();
14426         query = createPQExpBuffer();
14427
14428         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14429
14430         /* look up the foreign-data wrapper */
14431         appendPQExpBuffer(query, "SELECT fdwname "
14432                                           "FROM pg_foreign_data_wrapper w "
14433                                           "WHERE w.oid = '%u'",
14434                                           srvinfo->srvfdw);
14435         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14436         fdwname = PQgetvalue(res, 0, 0);
14437
14438         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14439         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14440         {
14441                 appendPQExpBufferStr(q, " TYPE ");
14442                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14443         }
14444         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14445         {
14446                 appendPQExpBufferStr(q, " VERSION ");
14447                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14448         }
14449
14450         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14451         appendPQExpBufferStr(q, fmtId(fdwname));
14452
14453         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14454                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14455
14456         appendPQExpBufferStr(q, ";\n");
14457
14458         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14459                                           qsrvname);
14460
14461         if (dopt->binary_upgrade)
14462                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14463                                                                                 "SERVER", qsrvname, NULL);
14464
14465         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14466                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14467                                          srvinfo->dobj.name,
14468                                          NULL,
14469                                          NULL,
14470                                          srvinfo->rolname,
14471                                          "SERVER", SECTION_PRE_DATA,
14472                                          q->data, delq->data, NULL,
14473                                          NULL, 0,
14474                                          NULL, NULL);
14475
14476         /* Dump Foreign Server Comments */
14477         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14478                 dumpComment(fout, "SERVER", qsrvname,
14479                                         NULL, srvinfo->rolname,
14480                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14481
14482         /* Handle the ACL */
14483         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14484                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14485                                 "FOREIGN SERVER", qsrvname, NULL,
14486                                 NULL, srvinfo->rolname,
14487                                 srvinfo->srvacl, srvinfo->rsrvacl,
14488                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14489
14490         /* Dump user mappings */
14491         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14492                 dumpUserMappings(fout,
14493                                                  srvinfo->dobj.name, NULL,
14494                                                  srvinfo->rolname,
14495                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14496
14497         free(qsrvname);
14498
14499         destroyPQExpBuffer(q);
14500         destroyPQExpBuffer(delq);
14501         destroyPQExpBuffer(query);
14502 }
14503
14504 /*
14505  * dumpUserMappings
14506  *
14507  * This routine is used to dump any user mappings associated with the
14508  * server handed to this routine. Should be called after ArchiveEntry()
14509  * for the server.
14510  */
14511 static void
14512 dumpUserMappings(Archive *fout,
14513                                  const char *servername, const char *namespace,
14514                                  const char *owner,
14515                                  CatalogId catalogId, DumpId dumpId)
14516 {
14517         PQExpBuffer q;
14518         PQExpBuffer delq;
14519         PQExpBuffer query;
14520         PQExpBuffer tag;
14521         PGresult   *res;
14522         int                     ntups;
14523         int                     i_usename;
14524         int                     i_umoptions;
14525         int                     i;
14526
14527         q = createPQExpBuffer();
14528         tag = createPQExpBuffer();
14529         delq = createPQExpBuffer();
14530         query = createPQExpBuffer();
14531
14532         /*
14533          * We read from the publicly accessible view pg_user_mappings, so as not
14534          * to fail if run by a non-superuser.  Note that the view will show
14535          * umoptions as null if the user hasn't got privileges for the associated
14536          * server; this means that pg_dump will dump such a mapping, but with no
14537          * OPTIONS clause.  A possible alternative is to skip such mappings
14538          * altogether, but it's not clear that that's an improvement.
14539          */
14540         appendPQExpBuffer(query,
14541                                           "SELECT usename, "
14542                                           "array_to_string(ARRAY("
14543                                           "SELECT quote_ident(option_name) || ' ' || "
14544                                           "quote_literal(option_value) "
14545                                           "FROM pg_options_to_table(umoptions) "
14546                                           "ORDER BY option_name"
14547                                           "), E',\n    ') AS umoptions "
14548                                           "FROM pg_user_mappings "
14549                                           "WHERE srvid = '%u' "
14550                                           "ORDER BY usename",
14551                                           catalogId.oid);
14552
14553         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14554
14555         ntups = PQntuples(res);
14556         i_usename = PQfnumber(res, "usename");
14557         i_umoptions = PQfnumber(res, "umoptions");
14558
14559         for (i = 0; i < ntups; i++)
14560         {
14561                 char       *usename;
14562                 char       *umoptions;
14563
14564                 usename = PQgetvalue(res, i, i_usename);
14565                 umoptions = PQgetvalue(res, i, i_umoptions);
14566
14567                 resetPQExpBuffer(q);
14568                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14569                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14570
14571                 if (umoptions && strlen(umoptions) > 0)
14572                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14573
14574                 appendPQExpBufferStr(q, ";\n");
14575
14576                 resetPQExpBuffer(delq);
14577                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14578                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14579
14580                 resetPQExpBuffer(tag);
14581                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14582                                                   usename, servername);
14583
14584                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14585                                          tag->data,
14586                                          namespace,
14587                                          NULL,
14588                                          owner,
14589                                          "USER MAPPING", SECTION_PRE_DATA,
14590                                          q->data, delq->data, NULL,
14591                                          &dumpId, 1,
14592                                          NULL, NULL);
14593         }
14594
14595         PQclear(res);
14596
14597         destroyPQExpBuffer(query);
14598         destroyPQExpBuffer(delq);
14599         destroyPQExpBuffer(tag);
14600         destroyPQExpBuffer(q);
14601 }
14602
14603 /*
14604  * Write out default privileges information
14605  */
14606 static void
14607 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14608 {
14609         DumpOptions *dopt = fout->dopt;
14610         PQExpBuffer q;
14611         PQExpBuffer tag;
14612         const char *type;
14613
14614         /* Skip if not to be dumped */
14615         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14616                 return;
14617
14618         q = createPQExpBuffer();
14619         tag = createPQExpBuffer();
14620
14621         switch (daclinfo->defaclobjtype)
14622         {
14623                 case DEFACLOBJ_RELATION:
14624                         type = "TABLES";
14625                         break;
14626                 case DEFACLOBJ_SEQUENCE:
14627                         type = "SEQUENCES";
14628                         break;
14629                 case DEFACLOBJ_FUNCTION:
14630                         type = "FUNCTIONS";
14631                         break;
14632                 case DEFACLOBJ_TYPE:
14633                         type = "TYPES";
14634                         break;
14635                 case DEFACLOBJ_NAMESPACE:
14636                         type = "SCHEMAS";
14637                         break;
14638                 default:
14639                         /* shouldn't get here */
14640                         exit_horribly(NULL,
14641                                                   "unrecognized object type in default privileges: %d\n",
14642                                                   (int) daclinfo->defaclobjtype);
14643                         type = "";                      /* keep compiler quiet */
14644         }
14645
14646         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14647
14648         /* build the actual command(s) for this tuple */
14649         if (!buildDefaultACLCommands(type,
14650                                                                  daclinfo->dobj.namespace != NULL ?
14651                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14652                                                                  daclinfo->defaclacl,
14653                                                                  daclinfo->rdefaclacl,
14654                                                                  daclinfo->initdefaclacl,
14655                                                                  daclinfo->initrdefaclacl,
14656                                                                  daclinfo->defaclrole,
14657                                                                  fout->remoteVersion,
14658                                                                  q))
14659                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14660                                           daclinfo->defaclacl);
14661
14662         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14663                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14664                                          tag->data,
14665                                          daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14666                                          NULL,
14667                                          daclinfo->defaclrole,
14668                                          "DEFAULT ACL", SECTION_POST_DATA,
14669                                          q->data, "", NULL,
14670                                          NULL, 0,
14671                                          NULL, NULL);
14672
14673         destroyPQExpBuffer(tag);
14674         destroyPQExpBuffer(q);
14675 }
14676
14677 /*----------
14678  * Write out grant/revoke information
14679  *
14680  * 'objCatId' is the catalog ID of the underlying object.
14681  * 'objDumpId' is the dump ID of the underlying object.
14682  * 'type' must be one of
14683  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14684  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14685  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14686  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14687  *              (Currently we assume that subname is only provided for table columns.)
14688  * 'nspname' is the namespace the object is in (NULL if none).
14689  * 'owner' is the owner, NULL if there is no owner (for languages).
14690  * 'acls' contains the ACL string of the object from the appropriate system
14691  *              catalog field; it will be passed to buildACLCommands for building the
14692  *              appropriate GRANT commands.
14693  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14694  *              object; it will be passed to buildACLCommands for building the
14695  *              appropriate REVOKE commands.
14696  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14697  *              privileges, to be recorded into pg_init_privs
14698  * 'initracls' In binary-upgrade mode, ACL string of the object's
14699  *              revoked-from-default privileges, to be recorded into pg_init_privs
14700  *
14701  * NB: initacls/initracls are needed because extensions can set privileges on
14702  * an object during the extension's script file and we record those into
14703  * pg_init_privs as that object's initial privileges.
14704  *----------
14705  */
14706 static void
14707 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14708                 const char *type, const char *name, const char *subname,
14709                 const char *nspname, const char *owner,
14710                 const char *acls, const char *racls,
14711                 const char *initacls, const char *initracls)
14712 {
14713         DumpOptions *dopt = fout->dopt;
14714         PQExpBuffer sql;
14715
14716         /* Do nothing if ACL dump is not enabled */
14717         if (dopt->aclsSkip)
14718                 return;
14719
14720         /* --data-only skips ACLs *except* BLOB ACLs */
14721         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14722                 return;
14723
14724         sql = createPQExpBuffer();
14725
14726         /*
14727          * Check to see if this object has had any initial ACLs included for it.
14728          * If so, we are in binary upgrade mode and these are the ACLs to turn
14729          * into GRANT and REVOKE statements to set and record the initial
14730          * privileges for an extension object.  Let the backend know that these
14731          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14732          * before and after.
14733          */
14734         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14735         {
14736                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14737                 if (!buildACLCommands(name, subname, nspname, type,
14738                                                           initacls, initracls, owner,
14739                                                           "", fout->remoteVersion, sql))
14740                         exit_horribly(NULL,
14741                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14742                                                   initacls, initracls, name, type);
14743                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14744         }
14745
14746         if (!buildACLCommands(name, subname, nspname, type,
14747                                                   acls, racls, owner,
14748                                                   "", fout->remoteVersion, sql))
14749                 exit_horribly(NULL,
14750                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14751                                           acls, racls, name, type);
14752
14753         if (sql->len > 0)
14754         {
14755                 PQExpBuffer tag = createPQExpBuffer();
14756
14757                 if (subname)
14758                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14759                 else
14760                         appendPQExpBuffer(tag, "%s %s", type, name);
14761
14762                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14763                                          tag->data, nspname,
14764                                          NULL,
14765                                          owner ? owner : "",
14766                                          "ACL", SECTION_NONE,
14767                                          sql->data, "", NULL,
14768                                          &(objDumpId), 1,
14769                                          NULL, NULL);
14770                 destroyPQExpBuffer(tag);
14771         }
14772
14773         destroyPQExpBuffer(sql);
14774 }
14775
14776 /*
14777  * dumpSecLabel
14778  *
14779  * This routine is used to dump any security labels associated with the
14780  * object handed to this routine. The routine takes the object type
14781  * and object name (ready to print, except for schema decoration), plus
14782  * the namespace and owner of the object (for labeling the ArchiveEntry),
14783  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14784  * plus the dump ID for the object (for setting a dependency).
14785  * If a matching pg_seclabel entry is found, it is dumped.
14786  *
14787  * Note: although this routine takes a dumpId for dependency purposes,
14788  * that purpose is just to mark the dependency in the emitted dump file
14789  * for possible future use by pg_restore.  We do NOT use it for determining
14790  * ordering of the label in the dump file, because this routine is called
14791  * after dependency sorting occurs.  This routine should be called just after
14792  * calling ArchiveEntry() for the specified object.
14793  */
14794 static void
14795 dumpSecLabel(Archive *fout, const char *type, const char *name,
14796                          const char *namespace, const char *owner,
14797                          CatalogId catalogId, int subid, DumpId dumpId)
14798 {
14799         DumpOptions *dopt = fout->dopt;
14800         SecLabelItem *labels;
14801         int                     nlabels;
14802         int                     i;
14803         PQExpBuffer query;
14804
14805         /* do nothing, if --no-security-labels is supplied */
14806         if (dopt->no_security_labels)
14807                 return;
14808
14809         /* Security labels are schema not data ... except blob labels are data */
14810         if (strcmp(type, "LARGE OBJECT") != 0)
14811         {
14812                 if (dopt->dataOnly)
14813                         return;
14814         }
14815         else
14816         {
14817                 /* We do dump blob security labels in binary-upgrade mode */
14818                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14819                         return;
14820         }
14821
14822         /* Search for security labels associated with catalogId, using table */
14823         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14824
14825         query = createPQExpBuffer();
14826
14827         for (i = 0; i < nlabels; i++)
14828         {
14829                 /*
14830                  * Ignore label entries for which the subid doesn't match.
14831                  */
14832                 if (labels[i].objsubid != subid)
14833                         continue;
14834
14835                 appendPQExpBuffer(query,
14836                                                   "SECURITY LABEL FOR %s ON %s ",
14837                                                   fmtId(labels[i].provider), type);
14838                 if (namespace && *namespace)
14839                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14840                 appendPQExpBuffer(query, "%s IS ", name);
14841                 appendStringLiteralAH(query, labels[i].label, fout);
14842                 appendPQExpBufferStr(query, ";\n");
14843         }
14844
14845         if (query->len > 0)
14846         {
14847                 PQExpBuffer tag = createPQExpBuffer();
14848
14849                 appendPQExpBuffer(tag, "%s %s", type, name);
14850                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14851                                          tag->data, namespace, NULL, owner,
14852                                          "SECURITY LABEL", SECTION_NONE,
14853                                          query->data, "", NULL,
14854                                          &(dumpId), 1,
14855                                          NULL, NULL);
14856                 destroyPQExpBuffer(tag);
14857         }
14858
14859         destroyPQExpBuffer(query);
14860 }
14861
14862 /*
14863  * dumpTableSecLabel
14864  *
14865  * As above, but dump security label for both the specified table (or view)
14866  * and its columns.
14867  */
14868 static void
14869 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14870 {
14871         DumpOptions *dopt = fout->dopt;
14872         SecLabelItem *labels;
14873         int                     nlabels;
14874         int                     i;
14875         PQExpBuffer query;
14876         PQExpBuffer target;
14877
14878         /* do nothing, if --no-security-labels is supplied */
14879         if (dopt->no_security_labels)
14880                 return;
14881
14882         /* SecLabel are SCHEMA not data */
14883         if (dopt->dataOnly)
14884                 return;
14885
14886         /* Search for comments associated with relation, using table */
14887         nlabels = findSecLabels(fout,
14888                                                         tbinfo->dobj.catId.tableoid,
14889                                                         tbinfo->dobj.catId.oid,
14890                                                         &labels);
14891
14892         /* If security labels exist, build SECURITY LABEL statements */
14893         if (nlabels <= 0)
14894                 return;
14895
14896         query = createPQExpBuffer();
14897         target = createPQExpBuffer();
14898
14899         for (i = 0; i < nlabels; i++)
14900         {
14901                 const char *colname;
14902                 const char *provider = labels[i].provider;
14903                 const char *label = labels[i].label;
14904                 int                     objsubid = labels[i].objsubid;
14905
14906                 resetPQExpBuffer(target);
14907                 if (objsubid == 0)
14908                 {
14909                         appendPQExpBuffer(target, "%s %s", reltypename,
14910                                                           fmtQualifiedDumpable(tbinfo));
14911                 }
14912                 else
14913                 {
14914                         colname = getAttrName(objsubid, tbinfo);
14915                         /* first fmtXXX result must be consumed before calling again */
14916                         appendPQExpBuffer(target, "COLUMN %s",
14917                                                           fmtQualifiedDumpable(tbinfo));
14918                         appendPQExpBuffer(target, ".%s", fmtId(colname));
14919                 }
14920                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14921                                                   fmtId(provider), target->data);
14922                 appendStringLiteralAH(query, label, fout);
14923                 appendPQExpBufferStr(query, ";\n");
14924         }
14925         if (query->len > 0)
14926         {
14927                 resetPQExpBuffer(target);
14928                 appendPQExpBuffer(target, "%s %s", reltypename,
14929                                                   fmtId(tbinfo->dobj.name));
14930                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14931                                          target->data,
14932                                          tbinfo->dobj.namespace->dobj.name,
14933                                          NULL, tbinfo->rolname,
14934                                          "SECURITY LABEL", SECTION_NONE,
14935                                          query->data, "", NULL,
14936                                          &(tbinfo->dobj.dumpId), 1,
14937                                          NULL, NULL);
14938         }
14939         destroyPQExpBuffer(query);
14940         destroyPQExpBuffer(target);
14941 }
14942
14943 /*
14944  * findSecLabels
14945  *
14946  * Find the security label(s), if any, associated with the given object.
14947  * All the objsubid values associated with the given classoid/objoid are
14948  * found with one search.
14949  */
14950 static int
14951 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14952 {
14953         /* static storage for table of security labels */
14954         static SecLabelItem *labels = NULL;
14955         static int      nlabels = -1;
14956
14957         SecLabelItem *middle = NULL;
14958         SecLabelItem *low;
14959         SecLabelItem *high;
14960         int                     nmatch;
14961
14962         /* Get security labels if we didn't already */
14963         if (nlabels < 0)
14964                 nlabels = collectSecLabels(fout, &labels);
14965
14966         if (nlabels <= 0)                       /* no labels, so no match is possible */
14967         {
14968                 *items = NULL;
14969                 return 0;
14970         }
14971
14972         /*
14973          * Do binary search to find some item matching the object.
14974          */
14975         low = &labels[0];
14976         high = &labels[nlabels - 1];
14977         while (low <= high)
14978         {
14979                 middle = low + (high - low) / 2;
14980
14981                 if (classoid < middle->classoid)
14982                         high = middle - 1;
14983                 else if (classoid > middle->classoid)
14984                         low = middle + 1;
14985                 else if (objoid < middle->objoid)
14986                         high = middle - 1;
14987                 else if (objoid > middle->objoid)
14988                         low = middle + 1;
14989                 else
14990                         break;                          /* found a match */
14991         }
14992
14993         if (low > high)                         /* no matches */
14994         {
14995                 *items = NULL;
14996                 return 0;
14997         }
14998
14999         /*
15000          * Now determine how many items match the object.  The search loop
15001          * invariant still holds: only items between low and high inclusive could
15002          * match.
15003          */
15004         nmatch = 1;
15005         while (middle > low)
15006         {
15007                 if (classoid != middle[-1].classoid ||
15008                         objoid != middle[-1].objoid)
15009                         break;
15010                 middle--;
15011                 nmatch++;
15012         }
15013
15014         *items = middle;
15015
15016         middle += nmatch;
15017         while (middle <= high)
15018         {
15019                 if (classoid != middle->classoid ||
15020                         objoid != middle->objoid)
15021                         break;
15022                 middle++;
15023                 nmatch++;
15024         }
15025
15026         return nmatch;
15027 }
15028
15029 /*
15030  * collectSecLabels
15031  *
15032  * Construct a table of all security labels available for database objects.
15033  * It's much faster to pull them all at once.
15034  *
15035  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15036  */
15037 static int
15038 collectSecLabels(Archive *fout, SecLabelItem **items)
15039 {
15040         PGresult   *res;
15041         PQExpBuffer query;
15042         int                     i_label;
15043         int                     i_provider;
15044         int                     i_classoid;
15045         int                     i_objoid;
15046         int                     i_objsubid;
15047         int                     ntups;
15048         int                     i;
15049         SecLabelItem *labels;
15050
15051         query = createPQExpBuffer();
15052
15053         appendPQExpBufferStr(query,
15054                                                  "SELECT label, provider, classoid, objoid, objsubid "
15055                                                  "FROM pg_catalog.pg_seclabel "
15056                                                  "ORDER BY classoid, objoid, objsubid");
15057
15058         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15059
15060         /* Construct lookup table containing OIDs in numeric form */
15061         i_label = PQfnumber(res, "label");
15062         i_provider = PQfnumber(res, "provider");
15063         i_classoid = PQfnumber(res, "classoid");
15064         i_objoid = PQfnumber(res, "objoid");
15065         i_objsubid = PQfnumber(res, "objsubid");
15066
15067         ntups = PQntuples(res);
15068
15069         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15070
15071         for (i = 0; i < ntups; i++)
15072         {
15073                 labels[i].label = PQgetvalue(res, i, i_label);
15074                 labels[i].provider = PQgetvalue(res, i, i_provider);
15075                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15076                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15077                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15078         }
15079
15080         /* Do NOT free the PGresult since we are keeping pointers into it */
15081         destroyPQExpBuffer(query);
15082
15083         *items = labels;
15084         return ntups;
15085 }
15086
15087 /*
15088  * dumpTable
15089  *        write out to fout the declarations (not data) of a user-defined table
15090  */
15091 static void
15092 dumpTable(Archive *fout, TableInfo *tbinfo)
15093 {
15094         DumpOptions *dopt = fout->dopt;
15095         char       *namecopy;
15096
15097         /*
15098          * noop if we are not dumping anything about this table, or if we are
15099          * doing a data-only dump
15100          */
15101         if (!tbinfo->dobj.dump || dopt->dataOnly)
15102                 return;
15103
15104         if (tbinfo->relkind == RELKIND_SEQUENCE)
15105                 dumpSequence(fout, tbinfo);
15106         else
15107                 dumpTableSchema(fout, tbinfo);
15108
15109         /* Handle the ACL here */
15110         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15111         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15112         {
15113                 const char *objtype =
15114                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15115
15116                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15117                                 objtype, namecopy, NULL,
15118                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15119                                 tbinfo->relacl, tbinfo->rrelacl,
15120                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15121         }
15122
15123         /*
15124          * Handle column ACLs, if any.  Note: we pull these with a separate query
15125          * rather than trying to fetch them during getTableAttrs, so that we won't
15126          * miss ACLs on system columns.
15127          */
15128         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15129         {
15130                 PQExpBuffer query = createPQExpBuffer();
15131                 PGresult   *res;
15132                 int                     i;
15133
15134                 if (fout->remoteVersion >= 90600)
15135                 {
15136                         PQExpBuffer acl_subquery = createPQExpBuffer();
15137                         PQExpBuffer racl_subquery = createPQExpBuffer();
15138                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15139                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15140
15141                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15142                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15143                                                         dopt->binary_upgrade);
15144
15145                         appendPQExpBuffer(query,
15146                                                           "SELECT at.attname, "
15147                                                           "%s AS attacl, "
15148                                                           "%s AS rattacl, "
15149                                                           "%s AS initattacl, "
15150                                                           "%s AS initrattacl "
15151                                                           "FROM pg_catalog.pg_attribute at "
15152                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15153                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15154                                                           "(at.attrelid = pip.objoid "
15155                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15156                                                           "AND at.attnum = pip.objsubid) "
15157                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15158                                                           "NOT at.attisdropped "
15159                                                           "AND ("
15160                                                           "%s IS NOT NULL OR "
15161                                                           "%s IS NOT NULL OR "
15162                                                           "%s IS NOT NULL OR "
15163                                                           "%s IS NOT NULL)"
15164                                                           "ORDER BY at.attnum",
15165                                                           acl_subquery->data,
15166                                                           racl_subquery->data,
15167                                                           initacl_subquery->data,
15168                                                           initracl_subquery->data,
15169                                                           tbinfo->dobj.catId.oid,
15170                                                           acl_subquery->data,
15171                                                           racl_subquery->data,
15172                                                           initacl_subquery->data,
15173                                                           initracl_subquery->data);
15174
15175                         destroyPQExpBuffer(acl_subquery);
15176                         destroyPQExpBuffer(racl_subquery);
15177                         destroyPQExpBuffer(initacl_subquery);
15178                         destroyPQExpBuffer(initracl_subquery);
15179                 }
15180                 else
15181                 {
15182                         appendPQExpBuffer(query,
15183                                                           "SELECT attname, attacl, NULL as rattacl, "
15184                                                           "NULL AS initattacl, NULL AS initrattacl "
15185                                                           "FROM pg_catalog.pg_attribute "
15186                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15187                                                           "AND attacl IS NOT NULL "
15188                                                           "ORDER BY attnum",
15189                                                           tbinfo->dobj.catId.oid);
15190                 }
15191
15192                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15193
15194                 for (i = 0; i < PQntuples(res); i++)
15195                 {
15196                         char       *attname = PQgetvalue(res, i, 0);
15197                         char       *attacl = PQgetvalue(res, i, 1);
15198                         char       *rattacl = PQgetvalue(res, i, 2);
15199                         char       *initattacl = PQgetvalue(res, i, 3);
15200                         char       *initrattacl = PQgetvalue(res, i, 4);
15201                         char       *attnamecopy;
15202
15203                         attnamecopy = pg_strdup(fmtId(attname));
15204                         /* Column's GRANT type is always TABLE */
15205                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15206                                         "TABLE", namecopy, attnamecopy,
15207                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15208                                         attacl, rattacl, initattacl, initrattacl);
15209                         free(attnamecopy);
15210                 }
15211                 PQclear(res);
15212                 destroyPQExpBuffer(query);
15213         }
15214
15215         free(namecopy);
15216
15217         return;
15218 }
15219
15220 /*
15221  * Create the AS clause for a view or materialized view. The semicolon is
15222  * stripped because a materialized view must add a WITH NO DATA clause.
15223  *
15224  * This returns a new buffer which must be freed by the caller.
15225  */
15226 static PQExpBuffer
15227 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15228 {
15229         PQExpBuffer query = createPQExpBuffer();
15230         PQExpBuffer result = createPQExpBuffer();
15231         PGresult   *res;
15232         int                     len;
15233
15234         /* Fetch the view definition */
15235         appendPQExpBuffer(query,
15236                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15237                                           tbinfo->dobj.catId.oid);
15238
15239         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15240
15241         if (PQntuples(res) != 1)
15242         {
15243                 if (PQntuples(res) < 1)
15244                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15245                                                   tbinfo->dobj.name);
15246                 else
15247                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15248                                                   tbinfo->dobj.name);
15249         }
15250
15251         len = PQgetlength(res, 0, 0);
15252
15253         if (len == 0)
15254                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15255                                           tbinfo->dobj.name);
15256
15257         /* Strip off the trailing semicolon so that other things may follow. */
15258         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15259         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15260
15261         PQclear(res);
15262         destroyPQExpBuffer(query);
15263
15264         return result;
15265 }
15266
15267 /*
15268  * Create a dummy AS clause for a view.  This is used when the real view
15269  * definition has to be postponed because of circular dependencies.
15270  * We must duplicate the view's external properties -- column names and types
15271  * (including collation) -- so that it works for subsequent references.
15272  *
15273  * This returns a new buffer which must be freed by the caller.
15274  */
15275 static PQExpBuffer
15276 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15277 {
15278         PQExpBuffer result = createPQExpBuffer();
15279         int                     j;
15280
15281         appendPQExpBufferStr(result, "SELECT");
15282
15283         for (j = 0; j < tbinfo->numatts; j++)
15284         {
15285                 if (j > 0)
15286                         appendPQExpBufferChar(result, ',');
15287                 appendPQExpBufferStr(result, "\n    ");
15288
15289                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15290
15291                 /*
15292                  * Must add collation if not default for the type, because CREATE OR
15293                  * REPLACE VIEW won't change it
15294                  */
15295                 if (OidIsValid(tbinfo->attcollation[j]))
15296                 {
15297                         CollInfo   *coll;
15298
15299                         coll = findCollationByOid(tbinfo->attcollation[j]);
15300                         if (coll)
15301                                 appendPQExpBuffer(result, " COLLATE %s",
15302                                                                   fmtQualifiedDumpable(coll));
15303                 }
15304
15305                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15306         }
15307
15308         return result;
15309 }
15310
15311 /*
15312  * dumpTableSchema
15313  *        write the declaration (not data) of one user-defined table or view
15314  */
15315 static void
15316 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15317 {
15318         DumpOptions *dopt = fout->dopt;
15319         PQExpBuffer q = createPQExpBuffer();
15320         PQExpBuffer delq = createPQExpBuffer();
15321         char       *qrelname;
15322         char       *qualrelname;
15323         int                     numParents;
15324         TableInfo **parents;
15325         int                     actual_atts;    /* number of attrs in this CREATE statement */
15326         const char *reltypename;
15327         char       *storage;
15328         int                     j,
15329                                 k;
15330
15331         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15332         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15333
15334
15335         if (tbinfo->hasoids)
15336                 write_msg(NULL,
15337                                   "WARNING: WITH OIDS is not supported anymore (table \"%s\")\n",
15338                                   qrelname);
15339
15340         if (dopt->binary_upgrade)
15341                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15342                                                                                                 tbinfo->dobj.catId.oid);
15343
15344         /* Is it a table or a view? */
15345         if (tbinfo->relkind == RELKIND_VIEW)
15346         {
15347                 PQExpBuffer result;
15348
15349                 /*
15350                  * Note: keep this code in sync with the is_view case in dumpRule()
15351                  */
15352
15353                 reltypename = "VIEW";
15354
15355                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15356
15357                 if (dopt->binary_upgrade)
15358                         binary_upgrade_set_pg_class_oids(fout, q,
15359                                                                                          tbinfo->dobj.catId.oid, false);
15360
15361                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15362
15363                 if (tbinfo->dummy_view)
15364                         result = createDummyViewAsClause(fout, tbinfo);
15365                 else
15366                 {
15367                         if (nonemptyReloptions(tbinfo->reloptions))
15368                         {
15369                                 appendPQExpBufferStr(q, " WITH (");
15370                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15371                                 appendPQExpBufferChar(q, ')');
15372                         }
15373                         result = createViewAsClause(fout, tbinfo);
15374                 }
15375                 appendPQExpBuffer(q, " AS\n%s", result->data);
15376                 destroyPQExpBuffer(result);
15377
15378                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15379                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15380                 appendPQExpBufferStr(q, ";\n");
15381         }
15382         else
15383         {
15384                 char       *ftoptions = NULL;
15385                 char       *srvname = NULL;
15386
15387                 switch (tbinfo->relkind)
15388                 {
15389                         case RELKIND_FOREIGN_TABLE:
15390                                 {
15391                                         PQExpBuffer query = createPQExpBuffer();
15392                                         PGresult   *res;
15393                                         int                     i_srvname;
15394                                         int                     i_ftoptions;
15395
15396                                         reltypename = "FOREIGN TABLE";
15397
15398                                         /* retrieve name of foreign server and generic options */
15399                                         appendPQExpBuffer(query,
15400                                                                           "SELECT fs.srvname, "
15401                                                                           "pg_catalog.array_to_string(ARRAY("
15402                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15403                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15404                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15405                                                                           "ORDER BY option_name"
15406                                                                           "), E',\n    ') AS ftoptions "
15407                                                                           "FROM pg_catalog.pg_foreign_table ft "
15408                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15409                                                                           "ON (fs.oid = ft.ftserver) "
15410                                                                           "WHERE ft.ftrelid = '%u'",
15411                                                                           tbinfo->dobj.catId.oid);
15412                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15413                                         i_srvname = PQfnumber(res, "srvname");
15414                                         i_ftoptions = PQfnumber(res, "ftoptions");
15415                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15416                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15417                                         PQclear(res);
15418                                         destroyPQExpBuffer(query);
15419                                         break;
15420                                 }
15421                         case RELKIND_MATVIEW:
15422                                 reltypename = "MATERIALIZED VIEW";
15423                                 break;
15424                         default:
15425                                 reltypename = "TABLE";
15426                 }
15427
15428                 numParents = tbinfo->numParents;
15429                 parents = tbinfo->parents;
15430
15431                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15432
15433                 if (dopt->binary_upgrade)
15434                         binary_upgrade_set_pg_class_oids(fout, q,
15435                                                                                          tbinfo->dobj.catId.oid, false);
15436
15437                 appendPQExpBuffer(q, "CREATE %s%s %s",
15438                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15439                                                   "UNLOGGED " : "",
15440                                                   reltypename,
15441                                                   qualrelname);
15442
15443                 /*
15444                  * Attach to type, if reloftype; except in case of a binary upgrade,
15445                  * we dump the table normally and attach it to the type afterward.
15446                  */
15447                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15448                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15449
15450                 /*
15451                  * If the table is a partition, dump it as such; except in the case of
15452                  * a binary upgrade, we dump the table normally and attach it to the
15453                  * parent afterward.
15454                  */
15455                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15456                 {
15457                         TableInfo  *parentRel = tbinfo->parents[0];
15458
15459                         /*
15460                          * With partitions, unlike inheritance, there can only be one
15461                          * parent.
15462                          */
15463                         if (tbinfo->numParents != 1)
15464                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15465                                                           tbinfo->numParents, tbinfo->dobj.name);
15466
15467                         appendPQExpBuffer(q, " PARTITION OF %s",
15468                                                           fmtQualifiedDumpable(parentRel));
15469                 }
15470
15471                 if (tbinfo->relkind != RELKIND_MATVIEW)
15472                 {
15473                         /* Dump the attributes */
15474                         actual_atts = 0;
15475                         for (j = 0; j < tbinfo->numatts; j++)
15476                         {
15477                                 /*
15478                                  * Normally, dump if it's locally defined in this table, and
15479                                  * not dropped.  But for binary upgrade, we'll dump all the
15480                                  * columns, and then fix up the dropped and nonlocal cases
15481                                  * below.
15482                                  */
15483                                 if (shouldPrintColumn(dopt, tbinfo, j))
15484                                 {
15485                                         /*
15486                                          * Default value --- suppress if to be printed separately.
15487                                          */
15488                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15489                                                                                            !tbinfo->attrdefs[j]->separate);
15490
15491                                         /*
15492                                          * Not Null constraint --- suppress if inherited, except
15493                                          * in binary-upgrade case where that won't work.
15494                                          */
15495                                         bool            has_notnull = (tbinfo->notnull[j] &&
15496                                                                                            (!tbinfo->inhNotNull[j] ||
15497                                                                                                 dopt->binary_upgrade));
15498
15499                                         /*
15500                                          * Skip column if fully defined by reloftype or the
15501                                          * partition parent.
15502                                          */
15503                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15504                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15505                                                 continue;
15506
15507                                         /* Format properly if not first attr */
15508                                         if (actual_atts == 0)
15509                                                 appendPQExpBufferStr(q, " (");
15510                                         else
15511                                                 appendPQExpBufferChar(q, ',');
15512                                         appendPQExpBufferStr(q, "\n    ");
15513                                         actual_atts++;
15514
15515                                         /* Attribute name */
15516                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15517
15518                                         if (tbinfo->attisdropped[j])
15519                                         {
15520                                                 /*
15521                                                  * ALTER TABLE DROP COLUMN clears
15522                                                  * pg_attribute.atttypid, so we will not have gotten a
15523                                                  * valid type name; insert INTEGER as a stopgap. We'll
15524                                                  * clean things up later.
15525                                                  */
15526                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15527                                                 /* Skip all the rest, too */
15528                                                 continue;
15529                                         }
15530
15531                                         /*
15532                                          * Attribute type
15533                                          *
15534                                          * In binary-upgrade mode, we always include the type. If
15535                                          * we aren't in binary-upgrade mode, then we skip the type
15536                                          * when creating a typed table ('OF type_name') or a
15537                                          * partition ('PARTITION OF'), since the type comes from
15538                                          * the parent/partitioned table.
15539                                          */
15540                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15541                                         {
15542                                                 appendPQExpBuffer(q, " %s",
15543                                                                                   tbinfo->atttypnames[j]);
15544                                         }
15545
15546                                         /* Add collation if not default for the type */
15547                                         if (OidIsValid(tbinfo->attcollation[j]))
15548                                         {
15549                                                 CollInfo   *coll;
15550
15551                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15552                                                 if (coll)
15553                                                         appendPQExpBuffer(q, " COLLATE %s",
15554                                                                                           fmtQualifiedDumpable(coll));
15555                                         }
15556
15557                                         if (has_default)
15558                                                 appendPQExpBuffer(q, " DEFAULT %s",
15559                                                                                   tbinfo->attrdefs[j]->adef_expr);
15560
15561                                         if (has_notnull)
15562                                                 appendPQExpBufferStr(q, " NOT NULL");
15563                                 }
15564                         }
15565
15566                         /*
15567                          * Add non-inherited CHECK constraints, if any.
15568                          */
15569                         for (j = 0; j < tbinfo->ncheck; j++)
15570                         {
15571                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15572
15573                                 if (constr->separate || !constr->conislocal)
15574                                         continue;
15575
15576                                 if (actual_atts == 0)
15577                                         appendPQExpBufferStr(q, " (\n    ");
15578                                 else
15579                                         appendPQExpBufferStr(q, ",\n    ");
15580
15581                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15582                                                                   fmtId(constr->dobj.name));
15583                                 appendPQExpBufferStr(q, constr->condef);
15584
15585                                 actual_atts++;
15586                         }
15587
15588                         if (actual_atts)
15589                                 appendPQExpBufferStr(q, "\n)");
15590                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15591                                            !dopt->binary_upgrade))
15592                         {
15593                                 /*
15594                                  * We must have a parenthesized attribute list, even though
15595                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15596                                  */
15597                                 appendPQExpBufferStr(q, " (\n)");
15598                         }
15599
15600                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15601                         {
15602                                 appendPQExpBufferChar(q, '\n');
15603                                 appendPQExpBufferStr(q, tbinfo->partbound);
15604                         }
15605
15606                         /* Emit the INHERITS clause, except if this is a partition. */
15607                         if (numParents > 0 &&
15608                                 !tbinfo->ispartition &&
15609                                 !dopt->binary_upgrade)
15610                         {
15611                                 appendPQExpBufferStr(q, "\nINHERITS (");
15612                                 for (k = 0; k < numParents; k++)
15613                                 {
15614                                         TableInfo  *parentRel = parents[k];
15615
15616                                         if (k > 0)
15617                                                 appendPQExpBufferStr(q, ", ");
15618                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15619                                 }
15620                                 appendPQExpBufferChar(q, ')');
15621                         }
15622
15623                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15624                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15625
15626                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15627                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15628                 }
15629
15630                 if (nonemptyReloptions(tbinfo->reloptions) ||
15631                         nonemptyReloptions(tbinfo->toast_reloptions))
15632                 {
15633                         bool            addcomma = false;
15634
15635                         appendPQExpBufferStr(q, "\nWITH (");
15636                         if (nonemptyReloptions(tbinfo->reloptions))
15637                         {
15638                                 addcomma = true;
15639                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15640                         }
15641                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15642                         {
15643                                 if (addcomma)
15644                                         appendPQExpBufferStr(q, ", ");
15645                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15646                                                                                 fout);
15647                         }
15648                         appendPQExpBufferChar(q, ')');
15649                 }
15650
15651                 /* Dump generic options if any */
15652                 if (ftoptions && ftoptions[0])
15653                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15654
15655                 /*
15656                  * For materialized views, create the AS clause just like a view. At
15657                  * this point, we always mark the view as not populated.
15658                  */
15659                 if (tbinfo->relkind == RELKIND_MATVIEW)
15660                 {
15661                         PQExpBuffer result;
15662
15663                         result = createViewAsClause(fout, tbinfo);
15664                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15665                                                           result->data);
15666                         destroyPQExpBuffer(result);
15667                 }
15668                 else
15669                         appendPQExpBufferStr(q, ";\n");
15670
15671                 /*
15672                  * in binary upgrade mode, update the catalog with any missing values
15673                  * that might be present.
15674                  */
15675                 if (dopt->binary_upgrade)
15676                 {
15677                         for (j = 0; j < tbinfo->numatts; j++)
15678                         {
15679                                 if (tbinfo->attmissingval[j][0] != '\0')
15680                                 {
15681                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15682                                         appendPQExpBufferStr(q,
15683                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15684                                         appendStringLiteralAH(q, qualrelname, fout);
15685                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15686                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15687                                         appendPQExpBufferStr(q, ",");
15688                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15689                                         appendPQExpBufferStr(q, ");\n\n");
15690                                 }
15691                         }
15692                 }
15693
15694                 /*
15695                  * To create binary-compatible heap files, we have to ensure the same
15696                  * physical column order, including dropped columns, as in the
15697                  * original.  Therefore, we create dropped columns above and drop them
15698                  * here, also updating their attlen/attalign values so that the
15699                  * dropped column can be skipped properly.  (We do not bother with
15700                  * restoring the original attbyval setting.)  Also, inheritance
15701                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15702                  * using an INHERITS clause --- the latter would possibly mess up the
15703                  * column order.  That also means we have to take care about setting
15704                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15705                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15706                  *
15707                  * We process foreign and partitioned tables here, even though they
15708                  * lack heap storage, because they can participate in inheritance
15709                  * relationships and we want this stuff to be consistent across the
15710                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15711                  * and matviews, even though they have storage, because we don't
15712                  * support altering or dropping columns in them, nor can they be part
15713                  * of inheritance trees.
15714                  */
15715                 if (dopt->binary_upgrade &&
15716                         (tbinfo->relkind == RELKIND_RELATION ||
15717                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15718                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15719                 {
15720                         for (j = 0; j < tbinfo->numatts; j++)
15721                         {
15722                                 if (tbinfo->attisdropped[j])
15723                                 {
15724                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15725                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15726                                                                           "SET attlen = %d, "
15727                                                                           "attalign = '%c', attbyval = false\n"
15728                                                                           "WHERE attname = ",
15729                                                                           tbinfo->attlen[j],
15730                                                                           tbinfo->attalign[j]);
15731                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15732                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15733                                         appendStringLiteralAH(q, qualrelname, fout);
15734                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15735
15736                                         if (tbinfo->relkind == RELKIND_RELATION ||
15737                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15738                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15739                                                                                   qualrelname);
15740                                         else
15741                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15742                                                                                   qualrelname);
15743                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15744                                                                           fmtId(tbinfo->attnames[j]));
15745                                 }
15746                                 else if (!tbinfo->attislocal[j])
15747                                 {
15748                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15749                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15750                                                                                  "SET attislocal = false\n"
15751                                                                                  "WHERE attname = ");
15752                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15753                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15754                                         appendStringLiteralAH(q, qualrelname, fout);
15755                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15756                                 }
15757                         }
15758
15759                         for (k = 0; k < tbinfo->ncheck; k++)
15760                         {
15761                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15762
15763                                 if (constr->separate || constr->conislocal)
15764                                         continue;
15765
15766                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15767                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15768                                                                   qualrelname);
15769                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15770                                                                   fmtId(constr->dobj.name));
15771                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15772                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15773                                                                          "SET conislocal = false\n"
15774                                                                          "WHERE contype = 'c' AND conname = ");
15775                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15776                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15777                                 appendStringLiteralAH(q, qualrelname, fout);
15778                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15779                         }
15780
15781                         if (numParents > 0)
15782                         {
15783                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15784                                 for (k = 0; k < numParents; k++)
15785                                 {
15786                                         TableInfo  *parentRel = parents[k];
15787
15788                                         /* In the partitioning case, we alter the parent */
15789                                         if (tbinfo->ispartition)
15790                                                 appendPQExpBuffer(q,
15791                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15792                                                                                   fmtQualifiedDumpable(parentRel));
15793                                         else
15794                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15795                                                                                   qualrelname);
15796
15797                                         /* Partition needs specifying the bounds */
15798                                         if (tbinfo->ispartition)
15799                                                 appendPQExpBuffer(q, "%s %s;\n",
15800                                                                                   qualrelname,
15801                                                                                   tbinfo->partbound);
15802                                         else
15803                                                 appendPQExpBuffer(q, "%s;\n",
15804                                                                                   fmtQualifiedDumpable(parentRel));
15805                                 }
15806                         }
15807
15808                         if (tbinfo->reloftype)
15809                         {
15810                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15811                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15812                                                                   qualrelname,
15813                                                                   tbinfo->reloftype);
15814                         }
15815                 }
15816
15817                 /*
15818                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15819                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15820                  * TOAST tables semi-independently, here we see them only as children
15821                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15822                  * child toast table is handled below.)
15823                  */
15824                 if (dopt->binary_upgrade &&
15825                         (tbinfo->relkind == RELKIND_RELATION ||
15826                          tbinfo->relkind == RELKIND_MATVIEW))
15827                 {
15828                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15829                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15830                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15831                                                           "WHERE oid = ",
15832                                                           tbinfo->frozenxid, tbinfo->minmxid);
15833                         appendStringLiteralAH(q, qualrelname, fout);
15834                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15835
15836                         if (tbinfo->toast_oid)
15837                         {
15838                                 /*
15839                                  * The toast table will have the same OID at restore, so we
15840                                  * can safely target it by OID.
15841                                  */
15842                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15843                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15844                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15845                                                                   "WHERE oid = '%u';\n",
15846                                                                   tbinfo->toast_frozenxid,
15847                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15848                         }
15849                 }
15850
15851                 /*
15852                  * In binary_upgrade mode, restore matviews' populated status by
15853                  * poking pg_class directly.  This is pretty ugly, but we can't use
15854                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15855                  * matview is not populated even though this matview is; in any case,
15856                  * we want to transfer the matview's heap storage, not run REFRESH.
15857                  */
15858                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15859                         tbinfo->relispopulated)
15860                 {
15861                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15862                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15863                                                                  "SET relispopulated = 't'\n"
15864                                                                  "WHERE oid = ");
15865                         appendStringLiteralAH(q, qualrelname, fout);
15866                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15867                 }
15868
15869                 /*
15870                  * Dump additional per-column properties that we can't handle in the
15871                  * main CREATE TABLE command.
15872                  */
15873                 for (j = 0; j < tbinfo->numatts; j++)
15874                 {
15875                         /* None of this applies to dropped columns */
15876                         if (tbinfo->attisdropped[j])
15877                                 continue;
15878
15879                         /*
15880                          * If we didn't dump the column definition explicitly above, and
15881                          * it is NOT NULL and did not inherit that property from a parent,
15882                          * we have to mark it separately.
15883                          */
15884                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
15885                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15886                         {
15887                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15888                                                                   qualrelname);
15889                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15890                                                                   fmtId(tbinfo->attnames[j]));
15891                         }
15892
15893                         /*
15894                          * Dump per-column statistics information. We only issue an ALTER
15895                          * TABLE statement if the attstattarget entry for this column is
15896                          * non-negative (i.e. it's not the default value)
15897                          */
15898                         if (tbinfo->attstattarget[j] >= 0)
15899                         {
15900                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15901                                                                   qualrelname);
15902                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15903                                                                   fmtId(tbinfo->attnames[j]));
15904                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15905                                                                   tbinfo->attstattarget[j]);
15906                         }
15907
15908                         /*
15909                          * Dump per-column storage information.  The statement is only
15910                          * dumped if the storage has been changed from the type's default.
15911                          */
15912                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15913                         {
15914                                 switch (tbinfo->attstorage[j])
15915                                 {
15916                                         case 'p':
15917                                                 storage = "PLAIN";
15918                                                 break;
15919                                         case 'e':
15920                                                 storage = "EXTERNAL";
15921                                                 break;
15922                                         case 'm':
15923                                                 storage = "MAIN";
15924                                                 break;
15925                                         case 'x':
15926                                                 storage = "EXTENDED";
15927                                                 break;
15928                                         default:
15929                                                 storage = NULL;
15930                                 }
15931
15932                                 /*
15933                                  * Only dump the statement if it's a storage type we recognize
15934                                  */
15935                                 if (storage != NULL)
15936                                 {
15937                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15938                                                                           qualrelname);
15939                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
15940                                                                           fmtId(tbinfo->attnames[j]));
15941                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
15942                                                                           storage);
15943                                 }
15944                         }
15945
15946                         /*
15947                          * Dump per-column attributes.
15948                          */
15949                         if (tbinfo->attoptions[j][0] != '\0')
15950                         {
15951                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15952                                                                   qualrelname);
15953                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15954                                                                   fmtId(tbinfo->attnames[j]));
15955                                 appendPQExpBuffer(q, "SET (%s);\n",
15956                                                                   tbinfo->attoptions[j]);
15957                         }
15958
15959                         /*
15960                          * Dump per-column fdw options.
15961                          */
15962                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15963                                 tbinfo->attfdwoptions[j][0] != '\0')
15964                         {
15965                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
15966                                                                   qualrelname);
15967                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15968                                                                   fmtId(tbinfo->attnames[j]));
15969                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
15970                                                                   tbinfo->attfdwoptions[j]);
15971                         }
15972                 }
15973
15974                 if (ftoptions)
15975                         free(ftoptions);
15976                 if (srvname)
15977                         free(srvname);
15978         }
15979
15980         /*
15981          * dump properties we only have ALTER TABLE syntax for
15982          */
15983         if ((tbinfo->relkind == RELKIND_RELATION ||
15984                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
15985                  tbinfo->relkind == RELKIND_MATVIEW) &&
15986                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
15987         {
15988                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
15989                 {
15990                         /* nothing to do, will be set when the index is dumped */
15991                 }
15992                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
15993                 {
15994                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
15995                                                           qualrelname);
15996                 }
15997                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
15998                 {
15999                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16000                                                           qualrelname);
16001                 }
16002         }
16003
16004         if (tbinfo->forcerowsec)
16005                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16006                                                   qualrelname);
16007
16008         if (dopt->binary_upgrade)
16009                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16010                                                                                 reltypename, qrelname,
16011                                                                                 tbinfo->dobj.namespace->dobj.name);
16012
16013         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16014                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16015                                          tbinfo->dobj.name,
16016                                          tbinfo->dobj.namespace->dobj.name,
16017                                          (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
16018                                          tbinfo->rolname,
16019                                          reltypename,
16020                                          tbinfo->postponed_def ?
16021                                          SECTION_POST_DATA : SECTION_PRE_DATA,
16022                                          q->data, delq->data, NULL,
16023                                          NULL, 0,
16024                                          NULL, NULL);
16025
16026
16027         /* Dump Table Comments */
16028         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16029                 dumpTableComment(fout, tbinfo, reltypename);
16030
16031         /* Dump Table Security Labels */
16032         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16033                 dumpTableSecLabel(fout, tbinfo, reltypename);
16034
16035         /* Dump comments on inlined table constraints */
16036         for (j = 0; j < tbinfo->ncheck; j++)
16037         {
16038                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16039
16040                 if (constr->separate || !constr->conislocal)
16041                         continue;
16042
16043                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16044                         dumpTableConstraintComment(fout, constr);
16045         }
16046
16047         destroyPQExpBuffer(q);
16048         destroyPQExpBuffer(delq);
16049         free(qrelname);
16050         free(qualrelname);
16051 }
16052
16053 /*
16054  * dumpAttrDef --- dump an attribute's default-value declaration
16055  */
16056 static void
16057 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16058 {
16059         DumpOptions *dopt = fout->dopt;
16060         TableInfo  *tbinfo = adinfo->adtable;
16061         int                     adnum = adinfo->adnum;
16062         PQExpBuffer q;
16063         PQExpBuffer delq;
16064         char       *qualrelname;
16065         char       *tag;
16066
16067         /* Skip if table definition not to be dumped */
16068         if (!tbinfo->dobj.dump || dopt->dataOnly)
16069                 return;
16070
16071         /* Skip if not "separate"; it was dumped in the table's definition */
16072         if (!adinfo->separate)
16073                 return;
16074
16075         q = createPQExpBuffer();
16076         delq = createPQExpBuffer();
16077
16078         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16079
16080         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16081                                           qualrelname);
16082         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16083                                           fmtId(tbinfo->attnames[adnum - 1]),
16084                                           adinfo->adef_expr);
16085
16086         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16087                                           qualrelname);
16088         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16089                                           fmtId(tbinfo->attnames[adnum - 1]));
16090
16091         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16092
16093         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16094                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16095                                          tag,
16096                                          tbinfo->dobj.namespace->dobj.name,
16097                                          NULL,
16098                                          tbinfo->rolname,
16099                                          "DEFAULT", SECTION_PRE_DATA,
16100                                          q->data, delq->data, NULL,
16101                                          NULL, 0,
16102                                          NULL, NULL);
16103
16104         free(tag);
16105         destroyPQExpBuffer(q);
16106         destroyPQExpBuffer(delq);
16107         free(qualrelname);
16108 }
16109
16110 /*
16111  * getAttrName: extract the correct name for an attribute
16112  *
16113  * The array tblInfo->attnames[] only provides names of user attributes;
16114  * if a system attribute number is supplied, we have to fake it.
16115  * We also do a little bit of bounds checking for safety's sake.
16116  */
16117 static const char *
16118 getAttrName(int attrnum, TableInfo *tblInfo)
16119 {
16120         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16121                 return tblInfo->attnames[attrnum - 1];
16122         switch (attrnum)
16123         {
16124                 case SelfItemPointerAttributeNumber:
16125                         return "ctid";
16126                 case MinTransactionIdAttributeNumber:
16127                         return "xmin";
16128                 case MinCommandIdAttributeNumber:
16129                         return "cmin";
16130                 case MaxTransactionIdAttributeNumber:
16131                         return "xmax";
16132                 case MaxCommandIdAttributeNumber:
16133                         return "cmax";
16134                 case TableOidAttributeNumber:
16135                         return "tableoid";
16136         }
16137         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16138                                   attrnum, tblInfo->dobj.name);
16139         return NULL;                            /* keep compiler quiet */
16140 }
16141
16142 /*
16143  * dumpIndex
16144  *        write out to fout a user-defined index
16145  */
16146 static void
16147 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16148 {
16149         DumpOptions *dopt = fout->dopt;
16150         TableInfo  *tbinfo = indxinfo->indextable;
16151         bool            is_constraint = (indxinfo->indexconstraint != 0);
16152         PQExpBuffer q;
16153         PQExpBuffer delq;
16154         char       *qindxname;
16155
16156         if (dopt->dataOnly)
16157                 return;
16158
16159         q = createPQExpBuffer();
16160         delq = createPQExpBuffer();
16161
16162         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16163
16164         /*
16165          * If there's an associated constraint, don't dump the index per se, but
16166          * do dump any comment for it.  (This is safe because dependency ordering
16167          * will have ensured the constraint is emitted first.)  Note that the
16168          * emitted comment has to be shown as depending on the constraint, not the
16169          * index, in such cases.
16170          */
16171         if (!is_constraint)
16172         {
16173                 char       *indstatcols = indxinfo->indstatcols;
16174                 char       *indstatvals = indxinfo->indstatvals;
16175                 char      **indstatcolsarray = NULL;
16176                 char      **indstatvalsarray = NULL;
16177                 int                     nstatcols;
16178                 int                     nstatvals;
16179
16180                 if (dopt->binary_upgrade)
16181                         binary_upgrade_set_pg_class_oids(fout, q,
16182                                                                                          indxinfo->dobj.catId.oid, true);
16183
16184                 /* Plain secondary index */
16185                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16186
16187                 /*
16188                  * Append ALTER TABLE commands as needed to set properties that we
16189                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16190                  * similar code in dumpConstraint!
16191                  */
16192
16193                 /* If the index is clustered, we need to record that. */
16194                 if (indxinfo->indisclustered)
16195                 {
16196                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16197                                                           fmtQualifiedDumpable(tbinfo));
16198                         /* index name is not qualified in this syntax */
16199                         appendPQExpBuffer(q, " ON %s;\n",
16200                                                           qindxname);
16201                 }
16202
16203                 /*
16204                  * If the index has any statistics on some of its columns, generate
16205                  * the associated ALTER INDEX queries.
16206                  */
16207                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16208                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16209                         nstatcols == nstatvals)
16210                 {
16211                         int                     j;
16212
16213                         for (j = 0; j < nstatcols; j++)
16214                         {
16215                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16216                                                                   fmtQualifiedDumpable(indxinfo));
16217
16218                                 /*
16219                                  * Note that this is a column number, so no quotes should be
16220                                  * used.
16221                                  */
16222                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16223                                                                   indstatcolsarray[j]);
16224                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16225                                                                   indstatvalsarray[j]);
16226                         }
16227                 }
16228
16229                 /* If the index defines identity, we need to record that. */
16230                 if (indxinfo->indisreplident)
16231                 {
16232                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16233                                                           fmtQualifiedDumpable(tbinfo));
16234                         /* index name is not qualified in this syntax */
16235                         appendPQExpBuffer(q, " INDEX %s;\n",
16236                                                           qindxname);
16237                 }
16238
16239                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16240                                                   fmtQualifiedDumpable(indxinfo));
16241
16242                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16243                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16244                                                  indxinfo->dobj.name,
16245                                                  tbinfo->dobj.namespace->dobj.name,
16246                                                  indxinfo->tablespace,
16247                                                  tbinfo->rolname,
16248                                                  "INDEX", SECTION_POST_DATA,
16249                                                  q->data, delq->data, NULL,
16250                                                  NULL, 0,
16251                                                  NULL, NULL);
16252
16253                 if (indstatcolsarray)
16254                         free(indstatcolsarray);
16255                 if (indstatvalsarray)
16256                         free(indstatvalsarray);
16257         }
16258
16259         /* Dump Index Comments */
16260         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16261                 dumpComment(fout, "INDEX", qindxname,
16262                                         tbinfo->dobj.namespace->dobj.name,
16263                                         tbinfo->rolname,
16264                                         indxinfo->dobj.catId, 0,
16265                                         is_constraint ? indxinfo->indexconstraint :
16266                                         indxinfo->dobj.dumpId);
16267
16268         destroyPQExpBuffer(q);
16269         destroyPQExpBuffer(delq);
16270         free(qindxname);
16271 }
16272
16273 /*
16274  * dumpIndexAttach
16275  *        write out to fout a partitioned-index attachment clause
16276  */
16277 static void
16278 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16279 {
16280         if (fout->dopt->dataOnly)
16281                 return;
16282
16283         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16284         {
16285                 PQExpBuffer q = createPQExpBuffer();
16286
16287                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16288                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16289                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16290                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16291
16292                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16293                                          attachinfo->dobj.name,
16294                                          attachinfo->dobj.namespace->dobj.name,
16295                                          NULL,
16296                                          "",
16297                                          "INDEX ATTACH", SECTION_POST_DATA,
16298                                          q->data, "", NULL,
16299                                          NULL, 0,
16300                                          NULL, NULL);
16301
16302                 destroyPQExpBuffer(q);
16303         }
16304 }
16305
16306 /*
16307  * dumpStatisticsExt
16308  *        write out to fout an extended statistics object
16309  */
16310 static void
16311 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16312 {
16313         DumpOptions *dopt = fout->dopt;
16314         PQExpBuffer q;
16315         PQExpBuffer delq;
16316         PQExpBuffer query;
16317         char       *qstatsextname;
16318         PGresult   *res;
16319         char       *stxdef;
16320
16321         /* Skip if not to be dumped */
16322         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16323                 return;
16324
16325         q = createPQExpBuffer();
16326         delq = createPQExpBuffer();
16327         query = createPQExpBuffer();
16328
16329         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16330
16331         appendPQExpBuffer(query, "SELECT "
16332                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16333                                           statsextinfo->dobj.catId.oid);
16334
16335         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16336
16337         stxdef = PQgetvalue(res, 0, 0);
16338
16339         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16340         appendPQExpBuffer(q, "%s;\n", stxdef);
16341
16342         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16343                                           fmtQualifiedDumpable(statsextinfo));
16344
16345         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16346                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16347                                          statsextinfo->dobj.dumpId,
16348                                          statsextinfo->dobj.name,
16349                                          statsextinfo->dobj.namespace->dobj.name,
16350                                          NULL,
16351                                          statsextinfo->rolname,
16352                                          "STATISTICS", SECTION_POST_DATA,
16353                                          q->data, delq->data, NULL,
16354                                          NULL, 0,
16355                                          NULL, NULL);
16356
16357         /* Dump Statistics Comments */
16358         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16359                 dumpComment(fout, "STATISTICS", qstatsextname,
16360                                         statsextinfo->dobj.namespace->dobj.name,
16361                                         statsextinfo->rolname,
16362                                         statsextinfo->dobj.catId, 0,
16363                                         statsextinfo->dobj.dumpId);
16364
16365         PQclear(res);
16366         destroyPQExpBuffer(q);
16367         destroyPQExpBuffer(delq);
16368         destroyPQExpBuffer(query);
16369         free(qstatsextname);
16370 }
16371
16372 /*
16373  * dumpConstraint
16374  *        write out to fout a user-defined constraint
16375  */
16376 static void
16377 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16378 {
16379         DumpOptions *dopt = fout->dopt;
16380         TableInfo  *tbinfo = coninfo->contable;
16381         PQExpBuffer q;
16382         PQExpBuffer delq;
16383         char       *tag = NULL;
16384
16385         /* Skip if not to be dumped */
16386         if (!coninfo->dobj.dump || dopt->dataOnly)
16387                 return;
16388
16389         q = createPQExpBuffer();
16390         delq = createPQExpBuffer();
16391
16392         if (coninfo->contype == 'p' ||
16393                 coninfo->contype == 'u' ||
16394                 coninfo->contype == 'x')
16395         {
16396                 /* Index-related constraint */
16397                 IndxInfo   *indxinfo;
16398                 int                     k;
16399
16400                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16401
16402                 if (indxinfo == NULL)
16403                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16404                                                   coninfo->dobj.name);
16405
16406                 if (dopt->binary_upgrade)
16407                         binary_upgrade_set_pg_class_oids(fout, q,
16408                                                                                          indxinfo->dobj.catId.oid, true);
16409
16410                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16411                                                   fmtQualifiedDumpable(tbinfo));
16412                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16413                                                   fmtId(coninfo->dobj.name));
16414
16415                 if (coninfo->condef)
16416                 {
16417                         /* pg_get_constraintdef should have provided everything */
16418                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16419                 }
16420                 else
16421                 {
16422                         appendPQExpBuffer(q, "%s (",
16423                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16424                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16425                         {
16426                                 int                     indkey = (int) indxinfo->indkeys[k];
16427                                 const char *attname;
16428
16429                                 if (indkey == InvalidAttrNumber)
16430                                         break;
16431                                 attname = getAttrName(indkey, tbinfo);
16432
16433                                 appendPQExpBuffer(q, "%s%s",
16434                                                                   (k == 0) ? "" : ", ",
16435                                                                   fmtId(attname));
16436                         }
16437
16438                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16439                                 appendPQExpBuffer(q, ") INCLUDE (");
16440
16441                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16442                         {
16443                                 int                     indkey = (int) indxinfo->indkeys[k];
16444                                 const char *attname;
16445
16446                                 if (indkey == InvalidAttrNumber)
16447                                         break;
16448                                 attname = getAttrName(indkey, tbinfo);
16449
16450                                 appendPQExpBuffer(q, "%s%s",
16451                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16452                                                                   fmtId(attname));
16453                         }
16454
16455                         appendPQExpBufferChar(q, ')');
16456
16457                         if (nonemptyReloptions(indxinfo->indreloptions))
16458                         {
16459                                 appendPQExpBufferStr(q, " WITH (");
16460                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16461                                 appendPQExpBufferChar(q, ')');
16462                         }
16463
16464                         if (coninfo->condeferrable)
16465                         {
16466                                 appendPQExpBufferStr(q, " DEFERRABLE");
16467                                 if (coninfo->condeferred)
16468                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16469                         }
16470
16471                         appendPQExpBufferStr(q, ";\n");
16472                 }
16473
16474                 /*
16475                  * Append ALTER TABLE commands as needed to set properties that we
16476                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16477                  * similar code in dumpIndex!
16478                  */
16479
16480                 /* If the index is clustered, we need to record that. */
16481                 if (indxinfo->indisclustered)
16482                 {
16483                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16484                                                           fmtQualifiedDumpable(tbinfo));
16485                         /* index name is not qualified in this syntax */
16486                         appendPQExpBuffer(q, " ON %s;\n",
16487                                                           fmtId(indxinfo->dobj.name));
16488                 }
16489
16490                 /* If the index defines identity, we need to record that. */
16491                 if (indxinfo->indisreplident)
16492                 {
16493                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16494                                                           fmtQualifiedDumpable(tbinfo));
16495                         /* index name is not qualified in this syntax */
16496                         appendPQExpBuffer(q, " INDEX %s;\n",
16497                                                           fmtId(indxinfo->dobj.name));
16498                 }
16499
16500                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16501                                                   fmtQualifiedDumpable(tbinfo));
16502                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16503                                                   fmtId(coninfo->dobj.name));
16504
16505                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16506
16507                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16508                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16509                                                  tag,
16510                                                  tbinfo->dobj.namespace->dobj.name,
16511                                                  indxinfo->tablespace,
16512                                                  tbinfo->rolname,
16513                                                  "CONSTRAINT", SECTION_POST_DATA,
16514                                                  q->data, delq->data, NULL,
16515                                                  NULL, 0,
16516                                                  NULL, NULL);
16517         }
16518         else if (coninfo->contype == 'f')
16519         {
16520                 char       *only;
16521
16522                 /*
16523                  * Foreign keys on partitioned tables are always declared as
16524                  * inheriting to partitions; for all other cases, emit them as
16525                  * applying ONLY directly to the named table, because that's how they
16526                  * work for regular inherited tables.
16527                  */
16528                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16529
16530                 /*
16531                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16532                  * current table data is not processed
16533                  */
16534                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16535                                                   only, fmtQualifiedDumpable(tbinfo));
16536                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16537                                                   fmtId(coninfo->dobj.name),
16538                                                   coninfo->condef);
16539
16540                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16541                                                   only, fmtQualifiedDumpable(tbinfo));
16542                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16543                                                   fmtId(coninfo->dobj.name));
16544
16545                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16546
16547                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16548                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16549                                                  tag,
16550                                                  tbinfo->dobj.namespace->dobj.name,
16551                                                  NULL,
16552                                                  tbinfo->rolname,
16553                                                  "FK CONSTRAINT", SECTION_POST_DATA,
16554                                                  q->data, delq->data, NULL,
16555                                                  NULL, 0,
16556                                                  NULL, NULL);
16557         }
16558         else if (coninfo->contype == 'c' && tbinfo)
16559         {
16560                 /* CHECK constraint on a table */
16561
16562                 /* Ignore if not to be dumped separately, or if it was inherited */
16563                 if (coninfo->separate && coninfo->conislocal)
16564                 {
16565                         /* not ONLY since we want it to propagate to children */
16566                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16567                                                           fmtQualifiedDumpable(tbinfo));
16568                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16569                                                           fmtId(coninfo->dobj.name),
16570                                                           coninfo->condef);
16571
16572                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16573                                                           fmtQualifiedDumpable(tbinfo));
16574                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16575                                                           fmtId(coninfo->dobj.name));
16576
16577                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16578
16579                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16580                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16581                                                          tag,
16582                                                          tbinfo->dobj.namespace->dobj.name,
16583                                                          NULL,
16584                                                          tbinfo->rolname,
16585                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16586                                                          q->data, delq->data, NULL,
16587                                                          NULL, 0,
16588                                                          NULL, NULL);
16589                 }
16590         }
16591         else if (coninfo->contype == 'c' && tbinfo == NULL)
16592         {
16593                 /* CHECK constraint on a domain */
16594                 TypeInfo   *tyinfo = coninfo->condomain;
16595
16596                 /* Ignore if not to be dumped separately */
16597                 if (coninfo->separate)
16598                 {
16599                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16600                                                           fmtQualifiedDumpable(tyinfo));
16601                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16602                                                           fmtId(coninfo->dobj.name),
16603                                                           coninfo->condef);
16604
16605                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16606                                                           fmtQualifiedDumpable(tyinfo));
16607                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16608                                                           fmtId(coninfo->dobj.name));
16609
16610                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16611
16612                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16613                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16614                                                          tag,
16615                                                          tyinfo->dobj.namespace->dobj.name,
16616                                                          NULL,
16617                                                          tyinfo->rolname,
16618                                                          "CHECK CONSTRAINT", SECTION_POST_DATA,
16619                                                          q->data, delq->data, NULL,
16620                                                          NULL, 0,
16621                                                          NULL, NULL);
16622                 }
16623         }
16624         else
16625         {
16626                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16627                                           coninfo->contype);
16628         }
16629
16630         /* Dump Constraint Comments --- only works for table constraints */
16631         if (tbinfo && coninfo->separate &&
16632                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16633                 dumpTableConstraintComment(fout, coninfo);
16634
16635         free(tag);
16636         destroyPQExpBuffer(q);
16637         destroyPQExpBuffer(delq);
16638 }
16639
16640 /*
16641  * dumpTableConstraintComment --- dump a constraint's comment if any
16642  *
16643  * This is split out because we need the function in two different places
16644  * depending on whether the constraint is dumped as part of CREATE TABLE
16645  * or as a separate ALTER command.
16646  */
16647 static void
16648 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16649 {
16650         TableInfo  *tbinfo = coninfo->contable;
16651         PQExpBuffer conprefix = createPQExpBuffer();
16652         char       *qtabname;
16653
16654         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16655
16656         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16657                                           fmtId(coninfo->dobj.name));
16658
16659         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16660                 dumpComment(fout, conprefix->data, qtabname,
16661                                         tbinfo->dobj.namespace->dobj.name,
16662                                         tbinfo->rolname,
16663                                         coninfo->dobj.catId, 0,
16664                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16665
16666         destroyPQExpBuffer(conprefix);
16667         free(qtabname);
16668 }
16669
16670 /*
16671  * findLastBuiltinOid_V71 -
16672  *
16673  * find the last built in oid
16674  *
16675  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16676  * pg_database entry for the current database.  (Note: current_database()
16677  * requires 7.3; pg_dump requires 8.0 now.)
16678  */
16679 static Oid
16680 findLastBuiltinOid_V71(Archive *fout)
16681 {
16682         PGresult   *res;
16683         Oid                     last_oid;
16684
16685         res = ExecuteSqlQueryForSingleRow(fout,
16686                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16687         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16688         PQclear(res);
16689
16690         return last_oid;
16691 }
16692
16693 /*
16694  * dumpSequence
16695  *        write the declaration (not data) of one user-defined sequence
16696  */
16697 static void
16698 dumpSequence(Archive *fout, TableInfo *tbinfo)
16699 {
16700         DumpOptions *dopt = fout->dopt;
16701         PGresult   *res;
16702         char       *startv,
16703                            *incby,
16704                            *maxv,
16705                            *minv,
16706                            *cache,
16707                            *seqtype;
16708         bool            cycled;
16709         bool            is_ascending;
16710         int64           default_minv,
16711                                 default_maxv;
16712         char            bufm[32],
16713                                 bufx[32];
16714         PQExpBuffer query = createPQExpBuffer();
16715         PQExpBuffer delqry = createPQExpBuffer();
16716         char       *qseqname;
16717
16718         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16719
16720         if (fout->remoteVersion >= 100000)
16721         {
16722                 appendPQExpBuffer(query,
16723                                                   "SELECT format_type(seqtypid, NULL), "
16724                                                   "seqstart, seqincrement, "
16725                                                   "seqmax, seqmin, "
16726                                                   "seqcache, seqcycle "
16727                                                   "FROM pg_catalog.pg_sequence "
16728                                                   "WHERE seqrelid = '%u'::oid",
16729                                                   tbinfo->dobj.catId.oid);
16730         }
16731         else if (fout->remoteVersion >= 80400)
16732         {
16733                 /*
16734                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16735                  *
16736                  * Note: it might seem that 'bigint' potentially needs to be
16737                  * schema-qualified, but actually that's a keyword.
16738                  */
16739                 appendPQExpBuffer(query,
16740                                                   "SELECT 'bigint' AS sequence_type, "
16741                                                   "start_value, increment_by, max_value, min_value, "
16742                                                   "cache_value, is_cycled FROM %s",
16743                                                   fmtQualifiedDumpable(tbinfo));
16744         }
16745         else
16746         {
16747                 appendPQExpBuffer(query,
16748                                                   "SELECT 'bigint' AS sequence_type, "
16749                                                   "0 AS start_value, increment_by, max_value, min_value, "
16750                                                   "cache_value, is_cycled FROM %s",
16751                                                   fmtQualifiedDumpable(tbinfo));
16752         }
16753
16754         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16755
16756         if (PQntuples(res) != 1)
16757         {
16758                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16759                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16760                                                                  PQntuples(res)),
16761                                   tbinfo->dobj.name, PQntuples(res));
16762                 exit_nicely(1);
16763         }
16764
16765         seqtype = PQgetvalue(res, 0, 0);
16766         startv = PQgetvalue(res, 0, 1);
16767         incby = PQgetvalue(res, 0, 2);
16768         maxv = PQgetvalue(res, 0, 3);
16769         minv = PQgetvalue(res, 0, 4);
16770         cache = PQgetvalue(res, 0, 5);
16771         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16772
16773         /* Calculate default limits for a sequence of this type */
16774         is_ascending = (incby[0] != '-');
16775         if (strcmp(seqtype, "smallint") == 0)
16776         {
16777                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16778                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16779         }
16780         else if (strcmp(seqtype, "integer") == 0)
16781         {
16782                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16783                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16784         }
16785         else if (strcmp(seqtype, "bigint") == 0)
16786         {
16787                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16788                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16789         }
16790         else
16791         {
16792                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16793                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16794         }
16795
16796         /*
16797          * 64-bit strtol() isn't very portable, so convert the limits to strings
16798          * and compare that way.
16799          */
16800         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16801         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16802
16803         /* Don't print minv/maxv if they match the respective default limit */
16804         if (strcmp(minv, bufm) == 0)
16805                 minv = NULL;
16806         if (strcmp(maxv, bufx) == 0)
16807                 maxv = NULL;
16808
16809         /*
16810          * Identity sequences are not to be dropped separately.
16811          */
16812         if (!tbinfo->is_identity_sequence)
16813         {
16814                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16815                                                   fmtQualifiedDumpable(tbinfo));
16816         }
16817
16818         resetPQExpBuffer(query);
16819
16820         if (dopt->binary_upgrade)
16821         {
16822                 binary_upgrade_set_pg_class_oids(fout, query,
16823                                                                                  tbinfo->dobj.catId.oid, false);
16824                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16825                                                                                                 tbinfo->dobj.catId.oid);
16826         }
16827
16828         if (tbinfo->is_identity_sequence)
16829         {
16830                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16831
16832                 appendPQExpBuffer(query,
16833                                                   "ALTER TABLE %s ",
16834                                                   fmtQualifiedDumpable(owning_tab));
16835                 appendPQExpBuffer(query,
16836                                                   "ALTER COLUMN %s ADD GENERATED ",
16837                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16838                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16839                         appendPQExpBuffer(query, "ALWAYS");
16840                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16841                         appendPQExpBuffer(query, "BY DEFAULT");
16842                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16843                                                   fmtQualifiedDumpable(tbinfo));
16844         }
16845         else
16846         {
16847                 appendPQExpBuffer(query,
16848                                                   "CREATE SEQUENCE %s\n",
16849                                                   fmtQualifiedDumpable(tbinfo));
16850
16851                 if (strcmp(seqtype, "bigint") != 0)
16852                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16853         }
16854
16855         if (fout->remoteVersion >= 80400)
16856                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16857
16858         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16859
16860         if (minv)
16861                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16862         else
16863                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16864
16865         if (maxv)
16866                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16867         else
16868                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16869
16870         appendPQExpBuffer(query,
16871                                           "    CACHE %s%s",
16872                                           cache, (cycled ? "\n    CYCLE" : ""));
16873
16874         if (tbinfo->is_identity_sequence)
16875                 appendPQExpBufferStr(query, "\n);\n");
16876         else
16877                 appendPQExpBufferStr(query, ";\n");
16878
16879         /* binary_upgrade:      no need to clear TOAST table oid */
16880
16881         if (dopt->binary_upgrade)
16882                 binary_upgrade_extension_member(query, &tbinfo->dobj,
16883                                                                                 "SEQUENCE", qseqname,
16884                                                                                 tbinfo->dobj.namespace->dobj.name);
16885
16886         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16887                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16888                                          tbinfo->dobj.name,
16889                                          tbinfo->dobj.namespace->dobj.name,
16890                                          NULL,
16891                                          tbinfo->rolname,
16892                                          "SEQUENCE", SECTION_PRE_DATA,
16893                                          query->data, delqry->data, NULL,
16894                                          NULL, 0,
16895                                          NULL, NULL);
16896
16897         /*
16898          * If the sequence is owned by a table column, emit the ALTER for it as a
16899          * separate TOC entry immediately following the sequence's own entry. It's
16900          * OK to do this rather than using full sorting logic, because the
16901          * dependency that tells us it's owned will have forced the table to be
16902          * created first.  We can't just include the ALTER in the TOC entry
16903          * because it will fail if we haven't reassigned the sequence owner to
16904          * match the table's owner.
16905          *
16906          * We need not schema-qualify the table reference because both sequence
16907          * and table must be in the same schema.
16908          */
16909         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
16910         {
16911                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16912
16913                 if (owning_tab == NULL)
16914                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
16915                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16916
16917                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16918                 {
16919                         resetPQExpBuffer(query);
16920                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16921                                                           fmtQualifiedDumpable(tbinfo));
16922                         appendPQExpBuffer(query, " OWNED BY %s",
16923                                                           fmtQualifiedDumpable(owning_tab));
16924                         appendPQExpBuffer(query, ".%s;\n",
16925                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16926
16927                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16928                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16929                                                          tbinfo->dobj.name,
16930                                                          tbinfo->dobj.namespace->dobj.name,
16931                                                          NULL,
16932                                                          tbinfo->rolname,
16933                                                          "SEQUENCE OWNED BY", SECTION_PRE_DATA,
16934                                                          query->data, "", NULL,
16935                                                          &(tbinfo->dobj.dumpId), 1,
16936                                                          NULL, NULL);
16937                 }
16938         }
16939
16940         /* Dump Sequence Comments and Security Labels */
16941         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16942                 dumpComment(fout, "SEQUENCE", qseqname,
16943                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16944                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16945
16946         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16947                 dumpSecLabel(fout, "SEQUENCE", qseqname,
16948                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16949                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16950
16951         PQclear(res);
16952
16953         destroyPQExpBuffer(query);
16954         destroyPQExpBuffer(delqry);
16955         free(qseqname);
16956 }
16957
16958 /*
16959  * dumpSequenceData
16960  *        write the data of one user-defined sequence
16961  */
16962 static void
16963 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16964 {
16965         TableInfo  *tbinfo = tdinfo->tdtable;
16966         PGresult   *res;
16967         char       *last;
16968         bool            called;
16969         PQExpBuffer query = createPQExpBuffer();
16970
16971         appendPQExpBuffer(query,
16972                                           "SELECT last_value, is_called FROM %s",
16973                                           fmtQualifiedDumpable(tbinfo));
16974
16975         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16976
16977         if (PQntuples(res) != 1)
16978         {
16979                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16980                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16981                                                                  PQntuples(res)),
16982                                   tbinfo->dobj.name, PQntuples(res));
16983                 exit_nicely(1);
16984         }
16985
16986         last = PQgetvalue(res, 0, 0);
16987         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
16988
16989         resetPQExpBuffer(query);
16990         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
16991         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
16992         appendPQExpBuffer(query, ", %s, %s);\n",
16993                                           last, (called ? "true" : "false"));
16994
16995         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
16996                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16997                                          tbinfo->dobj.name,
16998                                          tbinfo->dobj.namespace->dobj.name,
16999                                          NULL,
17000                                          tbinfo->rolname,
17001                                          "SEQUENCE SET", SECTION_DATA,
17002                                          query->data, "", NULL,
17003                                          &(tbinfo->dobj.dumpId), 1,
17004                                          NULL, NULL);
17005
17006         PQclear(res);
17007
17008         destroyPQExpBuffer(query);
17009 }
17010
17011 /*
17012  * dumpTrigger
17013  *        write the declaration of one user-defined table trigger
17014  */
17015 static void
17016 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17017 {
17018         DumpOptions *dopt = fout->dopt;
17019         TableInfo  *tbinfo = tginfo->tgtable;
17020         PQExpBuffer query;
17021         PQExpBuffer delqry;
17022         PQExpBuffer trigprefix;
17023         char       *qtabname;
17024         char       *tgargs;
17025         size_t          lentgargs;
17026         const char *p;
17027         int                     findx;
17028         char       *tag;
17029
17030         /*
17031          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17032          * created in the first place for non-dumpable triggers
17033          */
17034         if (dopt->dataOnly)
17035                 return;
17036
17037         query = createPQExpBuffer();
17038         delqry = createPQExpBuffer();
17039         trigprefix = createPQExpBuffer();
17040
17041         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17042
17043         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17044                                           fmtId(tginfo->dobj.name));
17045         appendPQExpBuffer(delqry, "ON %s;\n",
17046                                           fmtQualifiedDumpable(tbinfo));
17047
17048         if (tginfo->tgdef)
17049         {
17050                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17051         }
17052         else
17053         {
17054                 if (tginfo->tgisconstraint)
17055                 {
17056                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17057                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17058                 }
17059                 else
17060                 {
17061                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17062                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17063                 }
17064                 appendPQExpBufferStr(query, "\n    ");
17065
17066                 /* Trigger type */
17067                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17068                         appendPQExpBufferStr(query, "BEFORE");
17069                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17070                         appendPQExpBufferStr(query, "AFTER");
17071                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17072                         appendPQExpBufferStr(query, "INSTEAD OF");
17073                 else
17074                 {
17075                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17076                         exit_nicely(1);
17077                 }
17078
17079                 findx = 0;
17080                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17081                 {
17082                         appendPQExpBufferStr(query, " INSERT");
17083                         findx++;
17084                 }
17085                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17086                 {
17087                         if (findx > 0)
17088                                 appendPQExpBufferStr(query, " OR DELETE");
17089                         else
17090                                 appendPQExpBufferStr(query, " DELETE");
17091                         findx++;
17092                 }
17093                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17094                 {
17095                         if (findx > 0)
17096                                 appendPQExpBufferStr(query, " OR UPDATE");
17097                         else
17098                                 appendPQExpBufferStr(query, " UPDATE");
17099                         findx++;
17100                 }
17101                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17102                 {
17103                         if (findx > 0)
17104                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17105                         else
17106                                 appendPQExpBufferStr(query, " TRUNCATE");
17107                         findx++;
17108                 }
17109                 appendPQExpBuffer(query, " ON %s\n",
17110                                                   fmtQualifiedDumpable(tbinfo));
17111
17112                 if (tginfo->tgisconstraint)
17113                 {
17114                         if (OidIsValid(tginfo->tgconstrrelid))
17115                         {
17116                                 /* regclass output is already quoted */
17117                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17118                                                                   tginfo->tgconstrrelname);
17119                         }
17120                         if (!tginfo->tgdeferrable)
17121                                 appendPQExpBufferStr(query, "NOT ");
17122                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17123                         if (tginfo->tginitdeferred)
17124                                 appendPQExpBufferStr(query, "DEFERRED\n");
17125                         else
17126                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17127                 }
17128
17129                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17130                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17131                 else
17132                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17133
17134                 /* regproc output is already sufficiently quoted */
17135                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
17136                                                   tginfo->tgfname);
17137
17138                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17139                                                                                   &lentgargs);
17140                 p = tgargs;
17141                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17142                 {
17143                         /* find the embedded null that terminates this trigger argument */
17144                         size_t          tlen = strlen(p);
17145
17146                         if (p + tlen >= tgargs + lentgargs)
17147                         {
17148                                 /* hm, not found before end of bytea value... */
17149                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17150                                                   tginfo->tgargs,
17151                                                   tginfo->dobj.name,
17152                                                   tbinfo->dobj.name);
17153                                 exit_nicely(1);
17154                         }
17155
17156                         if (findx > 0)
17157                                 appendPQExpBufferStr(query, ", ");
17158                         appendStringLiteralAH(query, p, fout);
17159                         p += tlen + 1;
17160                 }
17161                 free(tgargs);
17162                 appendPQExpBufferStr(query, ");\n");
17163         }
17164
17165         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17166         {
17167                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17168                                                   fmtQualifiedDumpable(tbinfo));
17169                 switch (tginfo->tgenabled)
17170                 {
17171                         case 'D':
17172                         case 'f':
17173                                 appendPQExpBufferStr(query, "DISABLE");
17174                                 break;
17175                         case 'A':
17176                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17177                                 break;
17178                         case 'R':
17179                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17180                                 break;
17181                         default:
17182                                 appendPQExpBufferStr(query, "ENABLE");
17183                                 break;
17184                 }
17185                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17186                                                   fmtId(tginfo->dobj.name));
17187         }
17188
17189         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17190                                           fmtId(tginfo->dobj.name));
17191
17192         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17193
17194         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17195                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17196                                          tag,
17197                                          tbinfo->dobj.namespace->dobj.name,
17198                                          NULL,
17199                                          tbinfo->rolname,
17200                                          "TRIGGER", SECTION_POST_DATA,
17201                                          query->data, delqry->data, NULL,
17202                                          NULL, 0,
17203                                          NULL, NULL);
17204
17205         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17206                 dumpComment(fout, trigprefix->data, qtabname,
17207                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17208                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17209
17210         free(tag);
17211         destroyPQExpBuffer(query);
17212         destroyPQExpBuffer(delqry);
17213         destroyPQExpBuffer(trigprefix);
17214         free(qtabname);
17215 }
17216
17217 /*
17218  * dumpEventTrigger
17219  *        write the declaration of one user-defined event trigger
17220  */
17221 static void
17222 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17223 {
17224         DumpOptions *dopt = fout->dopt;
17225         PQExpBuffer query;
17226         PQExpBuffer delqry;
17227         char       *qevtname;
17228
17229         /* Skip if not to be dumped */
17230         if (!evtinfo->dobj.dump || dopt->dataOnly)
17231                 return;
17232
17233         query = createPQExpBuffer();
17234         delqry = createPQExpBuffer();
17235
17236         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17237
17238         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17239         appendPQExpBufferStr(query, qevtname);
17240         appendPQExpBufferStr(query, " ON ");
17241         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17242
17243         if (strcmp("", evtinfo->evttags) != 0)
17244         {
17245                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17246                 appendPQExpBufferStr(query, evtinfo->evttags);
17247                 appendPQExpBufferChar(query, ')');
17248         }
17249
17250         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
17251         appendPQExpBufferStr(query, evtinfo->evtfname);
17252         appendPQExpBufferStr(query, "();\n");
17253
17254         if (evtinfo->evtenabled != 'O')
17255         {
17256                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17257                                                   qevtname);
17258                 switch (evtinfo->evtenabled)
17259                 {
17260                         case 'D':
17261                                 appendPQExpBufferStr(query, "DISABLE");
17262                                 break;
17263                         case 'A':
17264                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17265                                 break;
17266                         case 'R':
17267                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17268                                 break;
17269                         default:
17270                                 appendPQExpBufferStr(query, "ENABLE");
17271                                 break;
17272                 }
17273                 appendPQExpBufferStr(query, ";\n");
17274         }
17275
17276         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17277                                           qevtname);
17278
17279         if (dopt->binary_upgrade)
17280                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17281                                                                                 "EVENT TRIGGER", qevtname, NULL);
17282
17283         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17284                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17285                                          evtinfo->dobj.name, NULL, NULL,
17286                                          evtinfo->evtowner,
17287                                          "EVENT TRIGGER", SECTION_POST_DATA,
17288                                          query->data, delqry->data, NULL,
17289                                          NULL, 0,
17290                                          NULL, NULL);
17291
17292         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17293                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17294                                         NULL, evtinfo->evtowner,
17295                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17296
17297         destroyPQExpBuffer(query);
17298         destroyPQExpBuffer(delqry);
17299         free(qevtname);
17300 }
17301
17302 /*
17303  * dumpRule
17304  *              Dump a rule
17305  */
17306 static void
17307 dumpRule(Archive *fout, RuleInfo *rinfo)
17308 {
17309         DumpOptions *dopt = fout->dopt;
17310         TableInfo  *tbinfo = rinfo->ruletable;
17311         bool            is_view;
17312         PQExpBuffer query;
17313         PQExpBuffer cmd;
17314         PQExpBuffer delcmd;
17315         PQExpBuffer ruleprefix;
17316         char       *qtabname;
17317         PGresult   *res;
17318         char       *tag;
17319
17320         /* Skip if not to be dumped */
17321         if (!rinfo->dobj.dump || dopt->dataOnly)
17322                 return;
17323
17324         /*
17325          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17326          * we do not want to dump it as a separate object.
17327          */
17328         if (!rinfo->separate)
17329                 return;
17330
17331         /*
17332          * If it's an ON SELECT rule, we want to print it as a view definition,
17333          * instead of a rule.
17334          */
17335         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17336
17337         query = createPQExpBuffer();
17338         cmd = createPQExpBuffer();
17339         delcmd = createPQExpBuffer();
17340         ruleprefix = createPQExpBuffer();
17341
17342         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17343
17344         if (is_view)
17345         {
17346                 PQExpBuffer result;
17347
17348                 /*
17349                  * We need OR REPLACE here because we'll be replacing a dummy view.
17350                  * Otherwise this should look largely like the regular view dump code.
17351                  */
17352                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17353                                                   fmtQualifiedDumpable(tbinfo));
17354                 if (nonemptyReloptions(tbinfo->reloptions))
17355                 {
17356                         appendPQExpBufferStr(cmd, " WITH (");
17357                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17358                         appendPQExpBufferChar(cmd, ')');
17359                 }
17360                 result = createViewAsClause(fout, tbinfo);
17361                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17362                 destroyPQExpBuffer(result);
17363                 if (tbinfo->checkoption != NULL)
17364                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17365                                                           tbinfo->checkoption);
17366                 appendPQExpBufferStr(cmd, ";\n");
17367         }
17368         else
17369         {
17370                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17371                 appendPQExpBuffer(query,
17372                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17373                                                   rinfo->dobj.catId.oid);
17374
17375                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17376
17377                 if (PQntuples(res) != 1)
17378                 {
17379                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17380                                           rinfo->dobj.name, tbinfo->dobj.name);
17381                         exit_nicely(1);
17382                 }
17383
17384                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17385
17386                 PQclear(res);
17387         }
17388
17389         /*
17390          * Add the command to alter the rules replication firing semantics if it
17391          * differs from the default.
17392          */
17393         if (rinfo->ev_enabled != 'O')
17394         {
17395                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17396                 switch (rinfo->ev_enabled)
17397                 {
17398                         case 'A':
17399                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17400                                                                   fmtId(rinfo->dobj.name));
17401                                 break;
17402                         case 'R':
17403                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17404                                                                   fmtId(rinfo->dobj.name));
17405                                 break;
17406                         case 'D':
17407                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17408                                                                   fmtId(rinfo->dobj.name));
17409                                 break;
17410                 }
17411         }
17412
17413         if (is_view)
17414         {
17415                 /*
17416                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17417                  * REPLACE VIEW to replace the rule with something with minimal
17418                  * dependencies.
17419                  */
17420                 PQExpBuffer result;
17421
17422                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17423                                                   fmtQualifiedDumpable(tbinfo));
17424                 result = createDummyViewAsClause(fout, tbinfo);
17425                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17426                 destroyPQExpBuffer(result);
17427         }
17428         else
17429         {
17430                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17431                                                   fmtId(rinfo->dobj.name));
17432                 appendPQExpBuffer(delcmd, "ON %s;\n",
17433                                                   fmtQualifiedDumpable(tbinfo));
17434         }
17435
17436         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17437                                           fmtId(rinfo->dobj.name));
17438
17439         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17440
17441         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17442                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17443                                          tag,
17444                                          tbinfo->dobj.namespace->dobj.name,
17445                                          NULL,
17446                                          tbinfo->rolname,
17447                                          "RULE", SECTION_POST_DATA,
17448                                          cmd->data, delcmd->data, NULL,
17449                                          NULL, 0,
17450                                          NULL, NULL);
17451
17452         /* Dump rule comments */
17453         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17454                 dumpComment(fout, ruleprefix->data, qtabname,
17455                                         tbinfo->dobj.namespace->dobj.name,
17456                                         tbinfo->rolname,
17457                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17458
17459         free(tag);
17460         destroyPQExpBuffer(query);
17461         destroyPQExpBuffer(cmd);
17462         destroyPQExpBuffer(delcmd);
17463         destroyPQExpBuffer(ruleprefix);
17464         free(qtabname);
17465 }
17466
17467 /*
17468  * getExtensionMembership --- obtain extension membership data
17469  *
17470  * We need to identify objects that are extension members as soon as they're
17471  * loaded, so that we can correctly determine whether they need to be dumped.
17472  * Generally speaking, extension member objects will get marked as *not* to
17473  * be dumped, as they will be recreated by the single CREATE EXTENSION
17474  * command.  However, in binary upgrade mode we still need to dump the members
17475  * individually.
17476  */
17477 void
17478 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17479                                            int numExtensions)
17480 {
17481         PQExpBuffer query;
17482         PGresult   *res;
17483         int                     ntups,
17484                                 nextmembers,
17485                                 i;
17486         int                     i_classid,
17487                                 i_objid,
17488                                 i_refobjid;
17489         ExtensionMemberId *extmembers;
17490         ExtensionInfo *ext;
17491
17492         /* Nothing to do if no extensions */
17493         if (numExtensions == 0)
17494                 return;
17495
17496         query = createPQExpBuffer();
17497
17498         /* refclassid constraint is redundant but may speed the search */
17499         appendPQExpBufferStr(query, "SELECT "
17500                                                  "classid, objid, refobjid "
17501                                                  "FROM pg_depend "
17502                                                  "WHERE refclassid = 'pg_extension'::regclass "
17503                                                  "AND deptype = 'e' "
17504                                                  "ORDER BY 3");
17505
17506         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17507
17508         ntups = PQntuples(res);
17509
17510         i_classid = PQfnumber(res, "classid");
17511         i_objid = PQfnumber(res, "objid");
17512         i_refobjid = PQfnumber(res, "refobjid");
17513
17514         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17515         nextmembers = 0;
17516
17517         /*
17518          * Accumulate data into extmembers[].
17519          *
17520          * Since we ordered the SELECT by referenced ID, we can expect that
17521          * multiple entries for the same extension will appear together; this
17522          * saves on searches.
17523          */
17524         ext = NULL;
17525
17526         for (i = 0; i < ntups; i++)
17527         {
17528                 CatalogId       objId;
17529                 Oid                     extId;
17530
17531                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17532                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17533                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17534
17535                 if (ext == NULL ||
17536                         ext->dobj.catId.oid != extId)
17537                         ext = findExtensionByOid(extId);
17538
17539                 if (ext == NULL)
17540                 {
17541                         /* shouldn't happen */
17542                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17543                         continue;
17544                 }
17545
17546                 extmembers[nextmembers].catId = objId;
17547                 extmembers[nextmembers].ext = ext;
17548                 nextmembers++;
17549         }
17550
17551         PQclear(res);
17552
17553         /* Remember the data for use later */
17554         setExtensionMembership(extmembers, nextmembers);
17555
17556         destroyPQExpBuffer(query);
17557 }
17558
17559 /*
17560  * processExtensionTables --- deal with extension configuration tables
17561  *
17562  * There are two parts to this process:
17563  *
17564  * 1. Identify and create dump records for extension configuration tables.
17565  *
17566  *        Extensions can mark tables as "configuration", which means that the user
17567  *        is able and expected to modify those tables after the extension has been
17568  *        loaded.  For these tables, we dump out only the data- the structure is
17569  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17570  *        foreign keys, which brings us to-
17571  *
17572  * 2. Record FK dependencies between configuration tables.
17573  *
17574  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17575  *        the data is loaded, we have to work out what the best order for reloading
17576  *        the data is, to avoid FK violations when the tables are restored.  This is
17577  *        not perfect- we can't handle circular dependencies and if any exist they
17578  *        will cause an invalid dump to be produced (though at least all of the data
17579  *        is included for a user to manually restore).  This is currently documented
17580  *        but perhaps we can provide a better solution in the future.
17581  */
17582 void
17583 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17584                                            int numExtensions)
17585 {
17586         DumpOptions *dopt = fout->dopt;
17587         PQExpBuffer query;
17588         PGresult   *res;
17589         int                     ntups,
17590                                 i;
17591         int                     i_conrelid,
17592                                 i_confrelid;
17593
17594         /* Nothing to do if no extensions */
17595         if (numExtensions == 0)
17596                 return;
17597
17598         /*
17599          * Identify extension configuration tables and create TableDataInfo
17600          * objects for them, ensuring their data will be dumped even though the
17601          * tables themselves won't be.
17602          *
17603          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17604          * user data in a configuration table is treated like schema data. This
17605          * seems appropriate since system data in a config table would get
17606          * reloaded by CREATE EXTENSION.
17607          */
17608         for (i = 0; i < numExtensions; i++)
17609         {
17610                 ExtensionInfo *curext = &(extinfo[i]);
17611                 char       *extconfig = curext->extconfig;
17612                 char       *extcondition = curext->extcondition;
17613                 char      **extconfigarray = NULL;
17614                 char      **extconditionarray = NULL;
17615                 int                     nconfigitems;
17616                 int                     nconditionitems;
17617
17618                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17619                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17620                         nconfigitems == nconditionitems)
17621                 {
17622                         int                     j;
17623
17624                         for (j = 0; j < nconfigitems; j++)
17625                         {
17626                                 TableInfo  *configtbl;
17627                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17628                                 bool            dumpobj =
17629                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17630
17631                                 configtbl = findTableByOid(configtbloid);
17632                                 if (configtbl == NULL)
17633                                         continue;
17634
17635                                 /*
17636                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17637                                  * unless the table or its schema is explicitly included
17638                                  */
17639                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17640                                 {
17641                                         /* check table explicitly requested */
17642                                         if (table_include_oids.head != NULL &&
17643                                                 simple_oid_list_member(&table_include_oids,
17644                                                                                            configtbloid))
17645                                                 dumpobj = true;
17646
17647                                         /* check table's schema explicitly requested */
17648                                         if (configtbl->dobj.namespace->dobj.dump &
17649                                                 DUMP_COMPONENT_DATA)
17650                                                 dumpobj = true;
17651                                 }
17652
17653                                 /* check table excluded by an exclusion switch */
17654                                 if (table_exclude_oids.head != NULL &&
17655                                         simple_oid_list_member(&table_exclude_oids,
17656                                                                                    configtbloid))
17657                                         dumpobj = false;
17658
17659                                 /* check schema excluded by an exclusion switch */
17660                                 if (simple_oid_list_member(&schema_exclude_oids,
17661                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17662                                         dumpobj = false;
17663
17664                                 if (dumpobj)
17665                                 {
17666                                         makeTableDataInfo(dopt, configtbl);
17667                                         if (configtbl->dataObj != NULL)
17668                                         {
17669                                                 if (strlen(extconditionarray[j]) > 0)
17670                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17671                                         }
17672                                 }
17673                         }
17674                 }
17675                 if (extconfigarray)
17676                         free(extconfigarray);
17677                 if (extconditionarray)
17678                         free(extconditionarray);
17679         }
17680
17681         /*
17682          * Now that all the TableInfoData objects have been created for all the
17683          * extensions, check their FK dependencies and register them to try and
17684          * dump the data out in an order that they can be restored in.
17685          *
17686          * Note that this is not a problem for user tables as their FKs are
17687          * recreated after the data has been loaded.
17688          */
17689
17690         query = createPQExpBuffer();
17691
17692         printfPQExpBuffer(query,
17693                                           "SELECT conrelid, confrelid "
17694                                           "FROM pg_constraint "
17695                                           "JOIN pg_depend ON (objid = confrelid) "
17696                                           "WHERE contype = 'f' "
17697                                           "AND refclassid = 'pg_extension'::regclass "
17698                                           "AND classid = 'pg_class'::regclass;");
17699
17700         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17701         ntups = PQntuples(res);
17702
17703         i_conrelid = PQfnumber(res, "conrelid");
17704         i_confrelid = PQfnumber(res, "confrelid");
17705
17706         /* Now get the dependencies and register them */
17707         for (i = 0; i < ntups; i++)
17708         {
17709                 Oid                     conrelid,
17710                                         confrelid;
17711                 TableInfo  *reftable,
17712                                    *contable;
17713
17714                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17715                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17716                 contable = findTableByOid(conrelid);
17717                 reftable = findTableByOid(confrelid);
17718
17719                 if (reftable == NULL ||
17720                         reftable->dataObj == NULL ||
17721                         contable == NULL ||
17722                         contable->dataObj == NULL)
17723                         continue;
17724
17725                 /*
17726                  * Make referencing TABLE_DATA object depend on the referenced table's
17727                  * TABLE_DATA object.
17728                  */
17729                 addObjectDependency(&contable->dataObj->dobj,
17730                                                         reftable->dataObj->dobj.dumpId);
17731         }
17732         PQclear(res);
17733         destroyPQExpBuffer(query);
17734 }
17735
17736 /*
17737  * getDependencies --- obtain available dependency data
17738  */
17739 static void
17740 getDependencies(Archive *fout)
17741 {
17742         PQExpBuffer query;
17743         PGresult   *res;
17744         int                     ntups,
17745                                 i;
17746         int                     i_classid,
17747                                 i_objid,
17748                                 i_refclassid,
17749                                 i_refobjid,
17750                                 i_deptype;
17751         DumpableObject *dobj,
17752                            *refdobj;
17753
17754         if (g_verbose)
17755                 write_msg(NULL, "reading dependency data\n");
17756
17757         query = createPQExpBuffer();
17758
17759         /*
17760          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17761          * already processed by getExtensionMembership.
17762          */
17763         appendPQExpBufferStr(query, "SELECT "
17764                                                  "classid, objid, refclassid, refobjid, deptype "
17765                                                  "FROM pg_depend "
17766                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17767                                                  "ORDER BY 1,2");
17768
17769         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17770
17771         ntups = PQntuples(res);
17772
17773         i_classid = PQfnumber(res, "classid");
17774         i_objid = PQfnumber(res, "objid");
17775         i_refclassid = PQfnumber(res, "refclassid");
17776         i_refobjid = PQfnumber(res, "refobjid");
17777         i_deptype = PQfnumber(res, "deptype");
17778
17779         /*
17780          * Since we ordered the SELECT by referencing ID, we can expect that
17781          * multiple entries for the same object will appear together; this saves
17782          * on searches.
17783          */
17784         dobj = NULL;
17785
17786         for (i = 0; i < ntups; i++)
17787         {
17788                 CatalogId       objId;
17789                 CatalogId       refobjId;
17790                 char            deptype;
17791
17792                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17793                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17794                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17795                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17796                 deptype = *(PQgetvalue(res, i, i_deptype));
17797
17798                 if (dobj == NULL ||
17799                         dobj->catId.tableoid != objId.tableoid ||
17800                         dobj->catId.oid != objId.oid)
17801                         dobj = findObjectByCatalogId(objId);
17802
17803                 /*
17804                  * Failure to find objects mentioned in pg_depend is not unexpected,
17805                  * since for example we don't collect info about TOAST tables.
17806                  */
17807                 if (dobj == NULL)
17808                 {
17809 #ifdef NOT_USED
17810                         fprintf(stderr, "no referencing object %u %u\n",
17811                                         objId.tableoid, objId.oid);
17812 #endif
17813                         continue;
17814                 }
17815
17816                 refdobj = findObjectByCatalogId(refobjId);
17817
17818                 if (refdobj == NULL)
17819                 {
17820 #ifdef NOT_USED
17821                         fprintf(stderr, "no referenced object %u %u\n",
17822                                         refobjId.tableoid, refobjId.oid);
17823 #endif
17824                         continue;
17825                 }
17826
17827                 /*
17828                  * Ordinarily, table rowtypes have implicit dependencies on their
17829                  * tables.  However, for a composite type the implicit dependency goes
17830                  * the other way in pg_depend; which is the right thing for DROP but
17831                  * it doesn't produce the dependency ordering we need. So in that one
17832                  * case, we reverse the direction of the dependency.
17833                  */
17834                 if (deptype == 'i' &&
17835                         dobj->objType == DO_TABLE &&
17836                         refdobj->objType == DO_TYPE)
17837                         addObjectDependency(refdobj, dobj->dumpId);
17838                 else
17839                         /* normal case */
17840                         addObjectDependency(dobj, refdobj->dumpId);
17841         }
17842
17843         PQclear(res);
17844
17845         destroyPQExpBuffer(query);
17846 }
17847
17848
17849 /*
17850  * createBoundaryObjects - create dummy DumpableObjects to represent
17851  * dump section boundaries.
17852  */
17853 static DumpableObject *
17854 createBoundaryObjects(void)
17855 {
17856         DumpableObject *dobjs;
17857
17858         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17859
17860         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17861         dobjs[0].catId = nilCatalogId;
17862         AssignDumpId(dobjs + 0);
17863         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17864
17865         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17866         dobjs[1].catId = nilCatalogId;
17867         AssignDumpId(dobjs + 1);
17868         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17869
17870         return dobjs;
17871 }
17872
17873 /*
17874  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17875  * section boundaries.
17876  */
17877 static void
17878 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17879                                                 DumpableObject *boundaryObjs)
17880 {
17881         DumpableObject *preDataBound = boundaryObjs + 0;
17882         DumpableObject *postDataBound = boundaryObjs + 1;
17883         int                     i;
17884
17885         for (i = 0; i < numObjs; i++)
17886         {
17887                 DumpableObject *dobj = dobjs[i];
17888
17889                 /*
17890                  * The classification of object types here must match the SECTION_xxx
17891                  * values assigned during subsequent ArchiveEntry calls!
17892                  */
17893                 switch (dobj->objType)
17894                 {
17895                         case DO_NAMESPACE:
17896                         case DO_EXTENSION:
17897                         case DO_TYPE:
17898                         case DO_SHELL_TYPE:
17899                         case DO_FUNC:
17900                         case DO_AGG:
17901                         case DO_OPERATOR:
17902                         case DO_ACCESS_METHOD:
17903                         case DO_OPCLASS:
17904                         case DO_OPFAMILY:
17905                         case DO_COLLATION:
17906                         case DO_CONVERSION:
17907                         case DO_TABLE:
17908                         case DO_ATTRDEF:
17909                         case DO_PROCLANG:
17910                         case DO_CAST:
17911                         case DO_DUMMY_TYPE:
17912                         case DO_TSPARSER:
17913                         case DO_TSDICT:
17914                         case DO_TSTEMPLATE:
17915                         case DO_TSCONFIG:
17916                         case DO_FDW:
17917                         case DO_FOREIGN_SERVER:
17918                         case DO_TRANSFORM:
17919                         case DO_BLOB:
17920                                 /* Pre-data objects: must come before the pre-data boundary */
17921                                 addObjectDependency(preDataBound, dobj->dumpId);
17922                                 break;
17923                         case DO_TABLE_DATA:
17924                         case DO_SEQUENCE_SET:
17925                         case DO_BLOB_DATA:
17926                                 /* Data objects: must come between the boundaries */
17927                                 addObjectDependency(dobj, preDataBound->dumpId);
17928                                 addObjectDependency(postDataBound, dobj->dumpId);
17929                                 break;
17930                         case DO_INDEX:
17931                         case DO_INDEX_ATTACH:
17932                         case DO_STATSEXT:
17933                         case DO_REFRESH_MATVIEW:
17934                         case DO_TRIGGER:
17935                         case DO_EVENT_TRIGGER:
17936                         case DO_DEFAULT_ACL:
17937                         case DO_POLICY:
17938                         case DO_PUBLICATION:
17939                         case DO_PUBLICATION_REL:
17940                         case DO_SUBSCRIPTION:
17941                                 /* Post-data objects: must come after the post-data boundary */
17942                                 addObjectDependency(dobj, postDataBound->dumpId);
17943                                 break;
17944                         case DO_RULE:
17945                                 /* Rules are post-data, but only if dumped separately */
17946                                 if (((RuleInfo *) dobj)->separate)
17947                                         addObjectDependency(dobj, postDataBound->dumpId);
17948                                 break;
17949                         case DO_CONSTRAINT:
17950                         case DO_FK_CONSTRAINT:
17951                                 /* Constraints are post-data, but only if dumped separately */
17952                                 if (((ConstraintInfo *) dobj)->separate)
17953                                         addObjectDependency(dobj, postDataBound->dumpId);
17954                                 break;
17955                         case DO_PRE_DATA_BOUNDARY:
17956                                 /* nothing to do */
17957                                 break;
17958                         case DO_POST_DATA_BOUNDARY:
17959                                 /* must come after the pre-data boundary */
17960                                 addObjectDependency(dobj, preDataBound->dumpId);
17961                                 break;
17962                 }
17963         }
17964 }
17965
17966
17967 /*
17968  * BuildArchiveDependencies - create dependency data for archive TOC entries
17969  *
17970  * The raw dependency data obtained by getDependencies() is not terribly
17971  * useful in an archive dump, because in many cases there are dependency
17972  * chains linking through objects that don't appear explicitly in the dump.
17973  * For example, a view will depend on its _RETURN rule while the _RETURN rule
17974  * will depend on other objects --- but the rule will not appear as a separate
17975  * object in the dump.  We need to adjust the view's dependencies to include
17976  * whatever the rule depends on that is included in the dump.
17977  *
17978  * Just to make things more complicated, there are also "special" dependencies
17979  * such as the dependency of a TABLE DATA item on its TABLE, which we must
17980  * not rearrange because pg_restore knows that TABLE DATA only depends on
17981  * its table.  In these cases we must leave the dependencies strictly as-is
17982  * even if they refer to not-to-be-dumped objects.
17983  *
17984  * To handle this, the convention is that "special" dependencies are created
17985  * during ArchiveEntry calls, and an archive TOC item that has any such
17986  * entries will not be touched here.  Otherwise, we recursively search the
17987  * DumpableObject data structures to build the correct dependencies for each
17988  * archive TOC item.
17989  */
17990 static void
17991 BuildArchiveDependencies(Archive *fout)
17992 {
17993         ArchiveHandle *AH = (ArchiveHandle *) fout;
17994         TocEntry   *te;
17995
17996         /* Scan all TOC entries in the archive */
17997         for (te = AH->toc->next; te != AH->toc; te = te->next)
17998         {
17999                 DumpableObject *dobj;
18000                 DumpId     *dependencies;
18001                 int                     nDeps;
18002                 int                     allocDeps;
18003
18004                 /* No need to process entries that will not be dumped */
18005                 if (te->reqs == 0)
18006                         continue;
18007                 /* Ignore entries that already have "special" dependencies */
18008                 if (te->nDeps > 0)
18009                         continue;
18010                 /* Otherwise, look up the item's original DumpableObject, if any */
18011                 dobj = findObjectByDumpId(te->dumpId);
18012                 if (dobj == NULL)
18013                         continue;
18014                 /* No work if it has no dependencies */
18015                 if (dobj->nDeps <= 0)
18016                         continue;
18017                 /* Set up work array */
18018                 allocDeps = 64;
18019                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18020                 nDeps = 0;
18021                 /* Recursively find all dumpable dependencies */
18022                 findDumpableDependencies(AH, dobj,
18023                                                                  &dependencies, &nDeps, &allocDeps);
18024                 /* And save 'em ... */
18025                 if (nDeps > 0)
18026                 {
18027                         dependencies = (DumpId *) pg_realloc(dependencies,
18028                                                                                                  nDeps * sizeof(DumpId));
18029                         te->dependencies = dependencies;
18030                         te->nDeps = nDeps;
18031                 }
18032                 else
18033                         free(dependencies);
18034         }
18035 }
18036
18037 /* Recursive search subroutine for BuildArchiveDependencies */
18038 static void
18039 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18040                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18041 {
18042         int                     i;
18043
18044         /*
18045          * Ignore section boundary objects: if we search through them, we'll
18046          * report lots of bogus dependencies.
18047          */
18048         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18049                 dobj->objType == DO_POST_DATA_BOUNDARY)
18050                 return;
18051
18052         for (i = 0; i < dobj->nDeps; i++)
18053         {
18054                 DumpId          depid = dobj->dependencies[i];
18055
18056                 if (TocIDRequired(AH, depid) != 0)
18057                 {
18058                         /* Object will be dumped, so just reference it as a dependency */
18059                         if (*nDeps >= *allocDeps)
18060                         {
18061                                 *allocDeps *= 2;
18062                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18063                                                                                                           *allocDeps * sizeof(DumpId));
18064                         }
18065                         (*dependencies)[*nDeps] = depid;
18066                         (*nDeps)++;
18067                 }
18068                 else
18069                 {
18070                         /*
18071                          * Object will not be dumped, so recursively consider its deps. We
18072                          * rely on the assumption that sortDumpableObjects already broke
18073                          * any dependency loops, else we might recurse infinitely.
18074                          */
18075                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18076
18077                         if (otherdobj)
18078                                 findDumpableDependencies(AH, otherdobj,
18079                                                                                  dependencies, nDeps, allocDeps);
18080                 }
18081         }
18082 }
18083
18084
18085 /*
18086  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18087  * given type OID.
18088  *
18089  * This does not guarantee to schema-qualify the output, so it should not
18090  * be used to create the target object name for CREATE or ALTER commands.
18091  *
18092  * TODO: there might be some value in caching the results.
18093  */
18094 static char *
18095 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18096 {
18097         char       *result;
18098         PQExpBuffer query;
18099         PGresult   *res;
18100
18101         if (oid == 0)
18102         {
18103                 if ((opts & zeroAsOpaque) != 0)
18104                         return pg_strdup(g_opaque_type);
18105                 else if ((opts & zeroAsAny) != 0)
18106                         return pg_strdup("'any'");
18107                 else if ((opts & zeroAsStar) != 0)
18108                         return pg_strdup("*");
18109                 else if ((opts & zeroAsNone) != 0)
18110                         return pg_strdup("NONE");
18111         }
18112
18113         query = createPQExpBuffer();
18114         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18115                                           oid);
18116
18117         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18118
18119         /* result of format_type is already quoted */
18120         result = pg_strdup(PQgetvalue(res, 0, 0));
18121
18122         PQclear(res);
18123         destroyPQExpBuffer(query);
18124
18125         return result;
18126 }
18127
18128 /*
18129  * Return a column list clause for the given relation.
18130  *
18131  * Special case: if there are no undropped columns in the relation, return
18132  * "", not an invalid "()" column list.
18133  */
18134 static const char *
18135 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18136 {
18137         int                     numatts = ti->numatts;
18138         char      **attnames = ti->attnames;
18139         bool       *attisdropped = ti->attisdropped;
18140         bool            needComma;
18141         int                     i;
18142
18143         appendPQExpBufferChar(buffer, '(');
18144         needComma = false;
18145         for (i = 0; i < numatts; i++)
18146         {
18147                 if (attisdropped[i])
18148                         continue;
18149                 if (needComma)
18150                         appendPQExpBufferStr(buffer, ", ");
18151                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18152                 needComma = true;
18153         }
18154
18155         if (!needComma)
18156                 return "";                              /* no undropped columns */
18157
18158         appendPQExpBufferChar(buffer, ')');
18159         return buffer->data;
18160 }
18161
18162 /*
18163  * Check if a reloptions array is nonempty.
18164  */
18165 static bool
18166 nonemptyReloptions(const char *reloptions)
18167 {
18168         /* Don't want to print it if it's just "{}" */
18169         return (reloptions != NULL && strlen(reloptions) > 2);
18170 }
18171
18172 /*
18173  * Format a reloptions array and append it to the given buffer.
18174  *
18175  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18176  */
18177 static void
18178 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18179                                                 const char *prefix, Archive *fout)
18180 {
18181         bool            res;
18182
18183         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18184                                                                 fout->std_strings);
18185         if (!res)
18186                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
18187 }