]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Correct copy/pasto in comment for REPLICA IDENTITY
[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-2014, 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
33 #include "postgres_fe.h"
34
35 #include <unistd.h>
36 #include <ctype.h>
37 #ifdef ENABLE_NLS
38 #include <locale.h>
39 #endif
40 #ifdef HAVE_TERMIOS_H
41 #include <termios.h>
42 #endif
43
44 #include "getopt_long.h"
45
46 #include "access/attnum.h"
47 #include "access/sysattr.h"
48 #include "access/transam.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_event_trigger.h"
53 #include "catalog/pg_largeobject.h"
54 #include "catalog/pg_largeobject_metadata.h"
55 #include "catalog/pg_proc.h"
56 #include "catalog/pg_trigger.h"
57 #include "catalog/pg_type.h"
58 #include "libpq/libpq-fs.h"
59
60 #include "pg_backup_archiver.h"
61 #include "pg_backup_db.h"
62 #include "pg_backup_utils.h"
63 #include "dumputils.h"
64 #include "parallel.h"
65
66
67 typedef struct
68 {
69         const char *descr;                      /* comment for an object */
70         Oid                     classoid;               /* object class (catalog OID) */
71         Oid                     objoid;                 /* object OID */
72         int                     objsubid;               /* subobject (table column #) */
73 } CommentItem;
74
75 typedef struct
76 {
77         const char *provider;           /* label provider of this security label */
78         const char *label;                      /* security label for an object */
79         Oid                     classoid;               /* object class (catalog OID) */
80         Oid                     objoid;                 /* object OID */
81         int                     objsubid;               /* subobject (table column #) */
82 } SecLabelItem;
83
84 /* global decls */
85 bool            g_verbose;                      /* User wants verbose narration of our
86                                                                  * activities. */
87
88 /* various user-settable parameters */
89 static bool     schemaOnly;
90 static bool     dataOnly;
91 static int      dumpSections;           /* bitmask of chosen sections */
92 static bool     aclsSkip;
93 static const char *lockWaitTimeout;
94
95 /* subquery used to convert user ID (eg, datdba) to user name */
96 static const char *username_subquery;
97
98 /* obsolete as of 7.3: */
99 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
100
101 /*
102  * Object inclusion/exclusion lists
103  *
104  * The string lists record the patterns given by command-line switches,
105  * which we then convert to lists of OIDs of matching objects.
106  */
107 static SimpleStringList schema_include_patterns = {NULL, NULL};
108 static SimpleOidList schema_include_oids = {NULL, NULL};
109 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
110 static SimpleOidList schema_exclude_oids = {NULL, NULL};
111
112 static SimpleStringList table_include_patterns = {NULL, NULL};
113 static SimpleOidList table_include_oids = {NULL, NULL};
114 static SimpleStringList table_exclude_patterns = {NULL, NULL};
115 static SimpleOidList table_exclude_oids = {NULL, NULL};
116 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
117 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
118
119 /* default, if no "inclusion" switches appear, is to dump everything */
120 static bool include_everything = true;
121
122 char            g_opaque_type[10];      /* name for the opaque type */
123
124 /* placeholders for the delimiters for comments */
125 char            g_comment_start[10];
126 char            g_comment_end[10];
127
128 static const CatalogId nilCatalogId = {0, 0};
129
130 /* flags for various command-line long options */
131 static int      binary_upgrade = 0;
132 static int      disable_dollar_quoting = 0;
133 static int      dump_inserts = 0;
134 static int      column_inserts = 0;
135 static int      if_exists = 0;
136 static int      no_security_labels = 0;
137 static int      no_synchronized_snapshots = 0;
138 static int      no_unlogged_table_data = 0;
139 static int      serializable_deferrable = 0;
140
141
142 static void help(const char *progname);
143 static void setup_connection(Archive *AH, const char *dumpencoding,
144                                  char *use_role);
145 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
146 static void expand_schema_name_patterns(Archive *fout,
147                                                         SimpleStringList *patterns,
148                                                         SimpleOidList *oids);
149 static void expand_table_name_patterns(Archive *fout,
150                                                    SimpleStringList *patterns,
151                                                    SimpleOidList *oids);
152 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
153 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
154 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
155 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
156 static void dumpComment(Archive *fout, const char *target,
157                         const char *namespace, const char *owner,
158                         CatalogId catalogId, int subid, DumpId dumpId);
159 static int findComments(Archive *fout, Oid classoid, Oid objoid,
160                          CommentItem **items);
161 static int      collectComments(Archive *fout, CommentItem **items);
162 static void dumpSecLabel(Archive *fout, const char *target,
163                          const char *namespace, const char *owner,
164                          CatalogId catalogId, int subid, DumpId dumpId);
165 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
166                           SecLabelItem **items);
167 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
168 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
169 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
170 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
171 static void dumpType(Archive *fout, TypeInfo *tyinfo);
172 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
173 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
174 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
175 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
176 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
178 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
179 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
180 static void dumpFunc(Archive *fout, FuncInfo *finfo);
181 static void dumpCast(Archive *fout, CastInfo *cast);
182 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
183 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
184 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
185 static void dumpCollation(Archive *fout, CollInfo *convinfo);
186 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
187 static void dumpRule(Archive *fout, RuleInfo *rinfo);
188 static void dumpAgg(Archive *fout, AggInfo *agginfo);
189 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
190 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
191 static void dumpTable(Archive *fout, TableInfo *tbinfo);
192 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
193 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
194 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
195 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
196 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
197 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
198 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
199 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
200 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
201 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
202 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
203 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
204 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
205 static void dumpUserMappings(Archive *fout,
206                                  const char *servername, const char *namespace,
207                                  const char *owner, CatalogId catalogId, DumpId dumpId);
208 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
209
210 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
211                 const char *type, const char *name, const char *subname,
212                 const char *tag, const char *nspname, const char *owner,
213                 const char *acls);
214
215 static void getDependencies(Archive *fout);
216 static void BuildArchiveDependencies(Archive *fout);
217 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
218                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
219
220 static DumpableObject *createBoundaryObjects(void);
221 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
222                                                 DumpableObject *boundaryObjs);
223
224 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
225 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
226 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
227 static void buildMatViewRefreshDependencies(Archive *fout);
228 static void getTableDataFKConstraints(void);
229 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
230                                                                            bool is_agg);
231 static char *format_function_arguments_old(Archive *fout,
232                                                           FuncInfo *finfo, int nallargs,
233                                                           char **allargtypes,
234                                                           char **argmodes,
235                                                           char **argnames);
236 static char *format_function_signature(Archive *fout,
237                                                   FuncInfo *finfo, bool honor_quotes);
238 static char *convertRegProcReference(Archive *fout,
239                                                 const char *proc);
240 static char *convertOperatorReference(Archive *fout, const char *opr);
241 static const char *convertTSFunction(Archive *fout, Oid funcOid);
242 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
243 static Oid      findLastBuiltinOid_V70(Archive *fout);
244 static void selectSourceSchema(Archive *fout, const char *schemaName);
245 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
246 static char *myFormatType(const char *typname, int32 typmod);
247 static void getBlobs(Archive *fout);
248 static void dumpBlob(Archive *fout, BlobInfo *binfo);
249 static int      dumpBlobs(Archive *fout, void *arg);
250 static void dumpDatabase(Archive *AH);
251 static void dumpEncoding(Archive *AH);
252 static void dumpStdStrings(Archive *AH);
253 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
254                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
255 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
256                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
257 static void binary_upgrade_set_pg_class_oids(Archive *fout,
258                                                                  PQExpBuffer upgrade_buffer,
259                                                                  Oid pg_class_oid, bool is_index);
260 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
261                                                                 DumpableObject *dobj,
262                                                                 const char *objlabel);
263 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
264 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
265 static char *get_synchronized_snapshot(Archive *fout);
266 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
267 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
268
269
270 int
271 main(int argc, char **argv)
272 {
273         int                     c;
274         const char *filename = NULL;
275         const char *format = "p";
276         const char *dbname = NULL;
277         const char *pghost = NULL;
278         const char *pgport = NULL;
279         const char *username = NULL;
280         const char *dumpencoding = NULL;
281         bool            oids = false;
282         TableInfo  *tblinfo;
283         int                     numTables;
284         DumpableObject **dobjs;
285         int                     numObjs;
286         DumpableObject *boundaryObjs;
287         int                     i;
288         int                     numWorkers = 1;
289         enum trivalue prompt_password = TRI_DEFAULT;
290         int                     compressLevel = -1;
291         int                     plainText = 0;
292         int                     outputClean = 0;
293         int                     outputCreateDB = 0;
294         bool            outputBlobs = false;
295         int                     outputNoOwner = 0;
296         char       *outputSuperuser = NULL;
297         char       *use_role = NULL;
298         int                     optindex;
299         RestoreOptions *ropt;
300         ArchiveFormat archiveFormat = archUnknown;
301         ArchiveMode archiveMode;
302         Archive    *fout;                       /* the script file */
303
304         static int      disable_triggers = 0;
305         static int      outputNoTablespaces = 0;
306         static int      use_setsessauth = 0;
307
308         static struct option long_options[] = {
309                 {"data-only", no_argument, NULL, 'a'},
310                 {"blobs", no_argument, NULL, 'b'},
311                 {"clean", no_argument, NULL, 'c'},
312                 {"create", no_argument, NULL, 'C'},
313                 {"dbname", required_argument, NULL, 'd'},
314                 {"file", required_argument, NULL, 'f'},
315                 {"format", required_argument, NULL, 'F'},
316                 {"host", required_argument, NULL, 'h'},
317                 {"ignore-version", no_argument, NULL, 'i'},
318                 {"jobs", 1, NULL, 'j'},
319                 {"no-reconnect", no_argument, NULL, 'R'},
320                 {"oids", no_argument, NULL, 'o'},
321                 {"no-owner", no_argument, NULL, 'O'},
322                 {"port", required_argument, NULL, 'p'},
323                 {"schema", required_argument, NULL, 'n'},
324                 {"exclude-schema", required_argument, NULL, 'N'},
325                 {"schema-only", no_argument, NULL, 's'},
326                 {"superuser", required_argument, NULL, 'S'},
327                 {"table", required_argument, NULL, 't'},
328                 {"exclude-table", required_argument, NULL, 'T'},
329                 {"no-password", no_argument, NULL, 'w'},
330                 {"password", no_argument, NULL, 'W'},
331                 {"username", required_argument, NULL, 'U'},
332                 {"verbose", no_argument, NULL, 'v'},
333                 {"no-privileges", no_argument, NULL, 'x'},
334                 {"no-acl", no_argument, NULL, 'x'},
335                 {"compress", required_argument, NULL, 'Z'},
336                 {"encoding", required_argument, NULL, 'E'},
337                 {"help", no_argument, NULL, '?'},
338                 {"version", no_argument, NULL, 'V'},
339
340                 /*
341                  * the following options don't have an equivalent short option letter
342                  */
343                 {"attribute-inserts", no_argument, &column_inserts, 1},
344                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
345                 {"column-inserts", no_argument, &column_inserts, 1},
346                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
347                 {"disable-triggers", no_argument, &disable_triggers, 1},
348                 {"exclude-table-data", required_argument, NULL, 4},
349                 {"if-exists", no_argument, &if_exists, 1},
350                 {"inserts", no_argument, &dump_inserts, 1},
351                 {"lock-wait-timeout", required_argument, NULL, 2},
352                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
353                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
354                 {"role", required_argument, NULL, 3},
355                 {"section", required_argument, NULL, 5},
356                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
357                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
358                 {"no-security-labels", no_argument, &no_security_labels, 1},
359                 {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
360                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
361
362                 {NULL, 0, NULL, 0}
363         };
364
365         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
366
367         /*
368          * Initialize what we need for parallel execution, especially for thread
369          * support on Windows.
370          */
371         init_parallel_dump_utils();
372
373         g_verbose = false;
374
375         strcpy(g_comment_start, "-- ");
376         g_comment_end[0] = '\0';
377         strcpy(g_opaque_type, "opaque");
378
379         dataOnly = schemaOnly = false;
380         dumpSections = DUMP_UNSECTIONED;
381         lockWaitTimeout = NULL;
382
383         progname = get_progname(argv[0]);
384
385         /* Set default options based on progname */
386         if (strcmp(progname, "pg_backup") == 0)
387                 format = "c";
388
389         if (argc > 1)
390         {
391                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
392                 {
393                         help(progname);
394                         exit_nicely(0);
395                 }
396                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
397                 {
398                         puts("pg_dump (PostgreSQL) " PG_VERSION);
399                         exit_nicely(0);
400                 }
401         }
402
403         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:n:N:oOp:RsS:t:T:U:vwWxZ:",
404                                                         long_options, &optindex)) != -1)
405         {
406                 switch (c)
407                 {
408                         case 'a':                       /* Dump data only */
409                                 dataOnly = true;
410                                 break;
411
412                         case 'b':                       /* Dump blobs */
413                                 outputBlobs = true;
414                                 break;
415
416                         case 'c':                       /* clean (i.e., drop) schema prior to create */
417                                 outputClean = 1;
418                                 break;
419
420                         case 'C':                       /* Create DB */
421                                 outputCreateDB = 1;
422                                 break;
423
424                         case 'd':                       /* database name */
425                                 dbname = pg_strdup(optarg);
426                                 break;
427
428                         case 'E':                       /* Dump encoding */
429                                 dumpencoding = pg_strdup(optarg);
430                                 break;
431
432                         case 'f':
433                                 filename = pg_strdup(optarg);
434                                 break;
435
436                         case 'F':
437                                 format = pg_strdup(optarg);
438                                 break;
439
440                         case 'h':                       /* server host */
441                                 pghost = pg_strdup(optarg);
442                                 break;
443
444                         case 'i':
445                                 /* ignored, deprecated option */
446                                 break;
447
448                         case 'j':                       /* number of dump jobs */
449                                 numWorkers = atoi(optarg);
450                                 break;
451
452                         case 'n':                       /* include schema(s) */
453                                 simple_string_list_append(&schema_include_patterns, optarg);
454                                 include_everything = false;
455                                 break;
456
457                         case 'N':                       /* exclude schema(s) */
458                                 simple_string_list_append(&schema_exclude_patterns, optarg);
459                                 break;
460
461                         case 'o':                       /* Dump oids */
462                                 oids = true;
463                                 break;
464
465                         case 'O':                       /* Don't reconnect to match owner */
466                                 outputNoOwner = 1;
467                                 break;
468
469                         case 'p':                       /* server port */
470                                 pgport = pg_strdup(optarg);
471                                 break;
472
473                         case 'R':
474                                 /* no-op, still accepted for backwards compatibility */
475                                 break;
476
477                         case 's':                       /* dump schema only */
478                                 schemaOnly = true;
479                                 break;
480
481                         case 'S':                       /* Username for superuser in plain text output */
482                                 outputSuperuser = pg_strdup(optarg);
483                                 break;
484
485                         case 't':                       /* include table(s) */
486                                 simple_string_list_append(&table_include_patterns, optarg);
487                                 include_everything = false;
488                                 break;
489
490                         case 'T':                       /* exclude table(s) */
491                                 simple_string_list_append(&table_exclude_patterns, optarg);
492                                 break;
493
494                         case 'U':
495                                 username = pg_strdup(optarg);
496                                 break;
497
498                         case 'v':                       /* verbose */
499                                 g_verbose = true;
500                                 break;
501
502                         case 'w':
503                                 prompt_password = TRI_NO;
504                                 break;
505
506                         case 'W':
507                                 prompt_password = TRI_YES;
508                                 break;
509
510                         case 'x':                       /* skip ACL dump */
511                                 aclsSkip = true;
512                                 break;
513
514                         case 'Z':                       /* Compression Level */
515                                 compressLevel = atoi(optarg);
516                                 break;
517
518                         case 0:
519                                 /* This covers the long options. */
520                                 break;
521
522                         case 2:                         /* lock-wait-timeout */
523                                 lockWaitTimeout = pg_strdup(optarg);
524                                 break;
525
526                         case 3:                         /* SET ROLE */
527                                 use_role = pg_strdup(optarg);
528                                 break;
529
530                         case 4:                         /* exclude table(s) data */
531                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
532                                 break;
533
534                         case 5:                         /* section */
535                                 set_dump_section(optarg, &dumpSections);
536                                 break;
537
538                         default:
539                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
540                                 exit_nicely(1);
541                 }
542         }
543
544         /*
545          * Non-option argument specifies database name as long as it wasn't
546          * already specified with -d / --dbname
547          */
548         if (optind < argc && dbname == NULL)
549                 dbname = argv[optind++];
550
551         /* Complain if any arguments remain */
552         if (optind < argc)
553         {
554                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
555                                 progname, argv[optind]);
556                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
557                                 progname);
558                 exit_nicely(1);
559         }
560
561         /* --column-inserts implies --inserts */
562         if (column_inserts)
563                 dump_inserts = 1;
564
565         if (dataOnly && schemaOnly)
566         {
567                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
568                 exit_nicely(1);
569         }
570
571         if (dataOnly && outputClean)
572         {
573                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
574                 exit_nicely(1);
575         }
576
577         if (dump_inserts && oids)
578         {
579                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
580                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
581                 exit_nicely(1);
582         }
583
584         if (if_exists && !outputClean)
585                 exit_horribly(NULL, "option --if-exists requires -c/--clean option\n");
586
587         /* Identify archive format to emit */
588         archiveFormat = parseArchiveFormat(format, &archiveMode);
589
590         /* archiveFormat specific setup */
591         if (archiveFormat == archNull)
592                 plainText = 1;
593
594         /* Custom and directory formats are compressed by default, others not */
595         if (compressLevel == -1)
596         {
597                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
598                         compressLevel = Z_DEFAULT_COMPRESSION;
599                 else
600                         compressLevel = 0;
601         }
602
603         /*
604          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
605          * parallel jobs because that's the maximum limit for the
606          * WaitForMultipleObjects() call.
607          */
608         if (numWorkers <= 0
609 #ifdef WIN32
610                 || numWorkers > MAXIMUM_WAIT_OBJECTS
611 #endif
612                 )
613                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
614
615         /* Parallel backup only in the directory archive format so far */
616         if (archiveFormat != archDirectory && numWorkers > 1)
617                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
618
619         /* Open the output file */
620         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
621                                                  setupDumpWorker);
622
623         /* Register the cleanup hook */
624         on_exit_close_archive(fout);
625
626         if (fout == NULL)
627                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
628
629         /* Let the archiver know how noisy to be */
630         fout->verbose = g_verbose;
631
632         /*
633          * We allow the server to be back to 7.0, and up to any minor release of
634          * our own major version.  (See also version check in pg_dumpall.c.)
635          */
636         fout->minRemoteVersion = 70000;
637         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
638
639         fout->numWorkers = numWorkers;
640
641         /*
642          * Open the database using the Archiver, so it knows about it. Errors mean
643          * death.
644          */
645         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
646         setup_connection(fout, dumpencoding, use_role);
647
648         /*
649          * Disable security label support if server version < v9.1.x (prevents
650          * access to nonexistent pg_seclabel catalog)
651          */
652         if (fout->remoteVersion < 90100)
653                 no_security_labels = 1;
654
655         /*
656          * When running against 9.0 or later, check if we are in recovery mode,
657          * which means we are on a hot standby.
658          */
659         if (fout->remoteVersion >= 90000)
660         {
661                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
662
663                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
664                 {
665                         /*
666                          * On hot standby slaves, never try to dump unlogged table data,
667                          * since it will just throw an error.
668                          */
669                         no_unlogged_table_data = true;
670                 }
671                 PQclear(res);
672         }
673
674         /* Select the appropriate subquery to convert user IDs to names */
675         if (fout->remoteVersion >= 80100)
676                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
677         else if (fout->remoteVersion >= 70300)
678                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
679         else
680                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
681
682         /* check the version for the synchronized snapshots feature */
683         if (numWorkers > 1 && fout->remoteVersion < 90200
684                 && !no_synchronized_snapshots)
685                 exit_horribly(NULL,
686                  "Synchronized snapshots are not supported by this server version.\n"
687                   "Run with --no-synchronized-snapshots instead if you do not need\n"
688                                           "synchronized snapshots.\n");
689
690         /* Find the last built-in OID, if needed */
691         if (fout->remoteVersion < 70300)
692         {
693                 if (fout->remoteVersion >= 70100)
694                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
695                                                                                                   PQdb(GetConnection(fout)));
696                 else
697                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
698                 if (g_verbose)
699                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
700         }
701
702         /* Expand schema selection patterns into OID lists */
703         if (schema_include_patterns.head != NULL)
704         {
705                 expand_schema_name_patterns(fout, &schema_include_patterns,
706                                                                         &schema_include_oids);
707                 if (schema_include_oids.head == NULL)
708                         exit_horribly(NULL, "No matching schemas were found\n");
709         }
710         expand_schema_name_patterns(fout, &schema_exclude_patterns,
711                                                                 &schema_exclude_oids);
712         /* non-matching exclusion patterns aren't an error */
713
714         /* Expand table selection patterns into OID lists */
715         if (table_include_patterns.head != NULL)
716         {
717                 expand_table_name_patterns(fout, &table_include_patterns,
718                                                                    &table_include_oids);
719                 if (table_include_oids.head == NULL)
720                         exit_horribly(NULL, "No matching tables were found\n");
721         }
722         expand_table_name_patterns(fout, &table_exclude_patterns,
723                                                            &table_exclude_oids);
724
725         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
726                                                            &tabledata_exclude_oids);
727
728         /* non-matching exclusion patterns aren't an error */
729
730         /*
731          * Dumping blobs is now default unless we saw an inclusion switch or -s
732          * ... but even if we did see one of these, -b turns it back on.
733          */
734         if (include_everything && !schemaOnly)
735                 outputBlobs = true;
736
737         /*
738          * Now scan the database and create DumpableObject structs for all the
739          * objects we intend to dump.
740          */
741         tblinfo = getSchemaData(fout, &numTables);
742
743         if (fout->remoteVersion < 80400)
744                 guessConstraintInheritance(tblinfo, numTables);
745
746         if (!schemaOnly)
747         {
748                 getTableData(tblinfo, numTables, oids);
749                 buildMatViewRefreshDependencies(fout);
750                 if (dataOnly)
751                         getTableDataFKConstraints();
752         }
753
754         if (outputBlobs)
755                 getBlobs(fout);
756
757         /*
758          * Collect dependency data to assist in ordering the objects.
759          */
760         getDependencies(fout);
761
762         /* Lastly, create dummy objects to represent the section boundaries */
763         boundaryObjs = createBoundaryObjects();
764
765         /* Get pointers to all the known DumpableObjects */
766         getDumpableObjects(&dobjs, &numObjs);
767
768         /*
769          * Add dummy dependencies to enforce the dump section ordering.
770          */
771         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
772
773         /*
774          * Sort the objects into a safe dump order (no forward references).
775          *
776          * In 7.3 or later, we can rely on dependency information to help us
777          * determine a safe order, so the initial sort is mostly for cosmetic
778          * purposes: we sort by name to ensure that logically identical schemas
779          * will dump identically.  Before 7.3 we don't have dependencies and we
780          * use OID ordering as an (unreliable) guide to creation order.
781          */
782         if (fout->remoteVersion >= 70300)
783                 sortDumpableObjectsByTypeName(dobjs, numObjs);
784         else
785                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
786
787         /* If we do a parallel dump, we want the largest tables to go first */
788         if (archiveFormat == archDirectory && numWorkers > 1)
789                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
790
791         sortDumpableObjects(dobjs, numObjs,
792                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
793
794         /*
795          * Create archive TOC entries for all the objects to be dumped, in a safe
796          * order.
797          */
798
799         /* First the special ENCODING and STDSTRINGS entries. */
800         dumpEncoding(fout);
801         dumpStdStrings(fout);
802
803         /* The database item is always next, unless we don't want it at all */
804         if (include_everything && !dataOnly)
805                 dumpDatabase(fout);
806
807         /* Now the rearrangeable objects. */
808         for (i = 0; i < numObjs; i++)
809                 dumpDumpableObject(fout, dobjs[i]);
810
811         /*
812          * Set up options info to ensure we dump what we want.
813          */
814         ropt = NewRestoreOptions();
815         ropt->filename = filename;
816         ropt->dropSchema = outputClean;
817         ropt->dataOnly = dataOnly;
818         ropt->schemaOnly = schemaOnly;
819         ropt->if_exists = if_exists;
820         ropt->dumpSections = dumpSections;
821         ropt->aclsSkip = aclsSkip;
822         ropt->superuser = outputSuperuser;
823         ropt->createDB = outputCreateDB;
824         ropt->noOwner = outputNoOwner;
825         ropt->noTablespace = outputNoTablespaces;
826         ropt->disable_triggers = disable_triggers;
827         ropt->use_setsessauth = use_setsessauth;
828
829         if (compressLevel == -1)
830                 ropt->compression = 0;
831         else
832                 ropt->compression = compressLevel;
833
834         ropt->suppressDumpWarnings = true;      /* We've already shown them */
835
836         SetArchiveRestoreOptions(fout, ropt);
837
838         /*
839          * The archive's TOC entries are now marked as to which ones will actually
840          * be output, so we can set up their dependency lists properly. This isn't
841          * necessary for plain-text output, though.
842          */
843         if (!plainText)
844                 BuildArchiveDependencies(fout);
845
846         /*
847          * And finally we can do the actual output.
848          *
849          * Note: for non-plain-text output formats, the output file is written
850          * inside CloseArchive().  This is, um, bizarre; but not worth changing
851          * right now.
852          */
853         if (plainText)
854                 RestoreArchive(fout);
855
856         CloseArchive(fout);
857
858         exit_nicely(0);
859 }
860
861
862 static void
863 help(const char *progname)
864 {
865         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
866         printf(_("Usage:\n"));
867         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
868
869         printf(_("\nGeneral options:\n"));
870         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
871         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
872                          "                               plain text (default))\n"));
873         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
874         printf(_("  -v, --verbose                verbose mode\n"));
875         printf(_("  -V, --version                output version information, then exit\n"));
876         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
877         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
878         printf(_("  -?, --help                   show this help, then exit\n"));
879
880         printf(_("\nOptions controlling the output content:\n"));
881         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
882         printf(_("  -b, --blobs                  include large objects in dump\n"));
883         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
884         printf(_("  -C, --create                 include commands to create database in dump\n"));
885         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
886         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
887         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
888         printf(_("  -o, --oids                   include OIDs in dump\n"));
889         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
890                          "                               plain-text format\n"));
891         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
892         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
893         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
894         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
895         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
896         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
897         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
898         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
899         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
900         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
901         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
902         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
903         printf(_("  --no-security-labels         do not dump security label assignments\n"));
904         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
905         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
906         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
907         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
908         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
909         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
910         printf(_("  --use-set-session-authorization\n"
911                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
912                          "                               ALTER OWNER commands to set ownership\n"));
913
914         printf(_("\nConnection options:\n"));
915         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
916         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
917         printf(_("  -p, --port=PORT          database server port number\n"));
918         printf(_("  -U, --username=NAME      connect as specified database user\n"));
919         printf(_("  -w, --no-password        never prompt for password\n"));
920         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
921         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
922
923         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
924                          "variable value is used.\n\n"));
925         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
926 }
927
928 static void
929 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
930 {
931         PGconn     *conn = GetConnection(AH);
932         const char *std_strings;
933
934         /*
935          * Set the client encoding if requested. If dumpencoding == NULL then
936          * either it hasn't been requested or we're a cloned connection and then
937          * this has already been set in CloneArchive according to the original
938          * connection encoding.
939          */
940         if (dumpencoding)
941         {
942                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
943                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
944                                                   dumpencoding);
945         }
946
947         /*
948          * Get the active encoding and the standard_conforming_strings setting, so
949          * we know how to escape strings.
950          */
951         AH->encoding = PQclientEncoding(conn);
952
953         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
954         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
955
956         /* Set the role if requested */
957         if (!use_role && AH->use_role)
958                 use_role = AH->use_role;
959
960         /* Set the role if requested */
961         if (use_role && AH->remoteVersion >= 80100)
962         {
963                 PQExpBuffer query = createPQExpBuffer();
964
965                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
966                 ExecuteSqlStatement(AH, query->data);
967                 destroyPQExpBuffer(query);
968
969                 /* save this for later use on parallel connections */
970                 if (!AH->use_role)
971                         AH->use_role = strdup(use_role);
972         }
973
974         /* Set the datestyle to ISO to ensure the dump's portability */
975         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
976
977         /* Likewise, avoid using sql_standard intervalstyle */
978         if (AH->remoteVersion >= 80400)
979                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
980
981         /*
982          * If supported, set extra_float_digits so that we can dump float data
983          * exactly (given correctly implemented float I/O code, anyway)
984          */
985         if (AH->remoteVersion >= 90000)
986                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
987         else if (AH->remoteVersion >= 70400)
988                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
989
990         /*
991          * If synchronized scanning is supported, disable it, to prevent
992          * unpredictable changes in row ordering across a dump and reload.
993          */
994         if (AH->remoteVersion >= 80300)
995                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
996
997         /*
998          * Disable timeouts if supported.
999          */
1000         if (AH->remoteVersion >= 70300)
1001                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1002         if (AH->remoteVersion >= 90300)
1003                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1004
1005         /*
1006          * Quote all identifiers, if requested.
1007          */
1008         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1009                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1010
1011         /*
1012          * Start transaction-snapshot mode transaction to dump consistent data.
1013          */
1014         ExecuteSqlStatement(AH, "BEGIN");
1015         if (AH->remoteVersion >= 90100)
1016         {
1017                 if (serializable_deferrable)
1018                         ExecuteSqlStatement(AH,
1019                                                                 "SET TRANSACTION ISOLATION LEVEL "
1020                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1021                 else
1022                         ExecuteSqlStatement(AH,
1023                                                                 "SET TRANSACTION ISOLATION LEVEL "
1024                                                                 "REPEATABLE READ, READ ONLY");
1025         }
1026         else if (AH->remoteVersion >= 70400)
1027         {
1028                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1029                 ExecuteSqlStatement(AH,
1030                                                         "SET TRANSACTION ISOLATION LEVEL "
1031                                                         "SERIALIZABLE READ ONLY");
1032         }
1033         else
1034                 ExecuteSqlStatement(AH,
1035                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1036
1037
1038
1039         if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
1040         {
1041                 if (AH->sync_snapshot_id)
1042                 {
1043                         PQExpBuffer query = createPQExpBuffer();
1044
1045                         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1046                         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1047                         ExecuteSqlStatement(AH, query->data);
1048                         destroyPQExpBuffer(query);
1049                 }
1050                 else
1051                         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1052         }
1053 }
1054
1055 static void
1056 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
1057 {
1058         setup_connection(AHX, NULL, NULL);
1059 }
1060
1061 static char *
1062 get_synchronized_snapshot(Archive *fout)
1063 {
1064         char       *query = "SELECT pg_export_snapshot()";
1065         char       *result;
1066         PGresult   *res;
1067
1068         res = ExecuteSqlQueryForSingleRow(fout, query);
1069         result = strdup(PQgetvalue(res, 0, 0));
1070         PQclear(res);
1071
1072         return result;
1073 }
1074
1075 static ArchiveFormat
1076 parseArchiveFormat(const char *format, ArchiveMode *mode)
1077 {
1078         ArchiveFormat archiveFormat;
1079
1080         *mode = archModeWrite;
1081
1082         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1083         {
1084                 /* This is used by pg_dumpall, and is not documented */
1085                 archiveFormat = archNull;
1086                 *mode = archModeAppend;
1087         }
1088         else if (pg_strcasecmp(format, "c") == 0)
1089                 archiveFormat = archCustom;
1090         else if (pg_strcasecmp(format, "custom") == 0)
1091                 archiveFormat = archCustom;
1092         else if (pg_strcasecmp(format, "d") == 0)
1093                 archiveFormat = archDirectory;
1094         else if (pg_strcasecmp(format, "directory") == 0)
1095                 archiveFormat = archDirectory;
1096         else if (pg_strcasecmp(format, "p") == 0)
1097                 archiveFormat = archNull;
1098         else if (pg_strcasecmp(format, "plain") == 0)
1099                 archiveFormat = archNull;
1100         else if (pg_strcasecmp(format, "t") == 0)
1101                 archiveFormat = archTar;
1102         else if (pg_strcasecmp(format, "tar") == 0)
1103                 archiveFormat = archTar;
1104         else
1105                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1106         return archiveFormat;
1107 }
1108
1109 /*
1110  * Find the OIDs of all schemas matching the given list of patterns,
1111  * and append them to the given OID list.
1112  */
1113 static void
1114 expand_schema_name_patterns(Archive *fout,
1115                                                         SimpleStringList *patterns,
1116                                                         SimpleOidList *oids)
1117 {
1118         PQExpBuffer query;
1119         PGresult   *res;
1120         SimpleStringListCell *cell;
1121         int                     i;
1122
1123         if (patterns->head == NULL)
1124                 return;                                 /* nothing to do */
1125
1126         if (fout->remoteVersion < 70300)
1127                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1128
1129         query = createPQExpBuffer();
1130
1131         /*
1132          * We use UNION ALL rather than UNION; this might sometimes result in
1133          * duplicate entries in the OID list, but we don't care.
1134          */
1135
1136         for (cell = patterns->head; cell; cell = cell->next)
1137         {
1138                 if (cell != patterns->head)
1139                         appendPQExpBufferStr(query, "UNION ALL\n");
1140                 appendPQExpBuffer(query,
1141                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1142                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1143                                                           false, NULL, "n.nspname", NULL, NULL);
1144         }
1145
1146         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1147
1148         for (i = 0; i < PQntuples(res); i++)
1149         {
1150                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1151         }
1152
1153         PQclear(res);
1154         destroyPQExpBuffer(query);
1155 }
1156
1157 /*
1158  * Find the OIDs of all tables matching the given list of patterns,
1159  * and append them to the given OID list.
1160  */
1161 static void
1162 expand_table_name_patterns(Archive *fout,
1163                                                    SimpleStringList *patterns, SimpleOidList *oids)
1164 {
1165         PQExpBuffer query;
1166         PGresult   *res;
1167         SimpleStringListCell *cell;
1168         int                     i;
1169
1170         if (patterns->head == NULL)
1171                 return;                                 /* nothing to do */
1172
1173         query = createPQExpBuffer();
1174
1175         /*
1176          * We use UNION ALL rather than UNION; this might sometimes result in
1177          * duplicate entries in the OID list, but we don't care.
1178          */
1179
1180         for (cell = patterns->head; cell; cell = cell->next)
1181         {
1182                 if (cell != patterns->head)
1183                         appendPQExpBufferStr(query, "UNION ALL\n");
1184                 appendPQExpBuffer(query,
1185                                                   "SELECT c.oid"
1186                                                   "\nFROM pg_catalog.pg_class c"
1187                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1188                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1189                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1190                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1191                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1192                                                           false, "n.nspname", "c.relname", NULL,
1193                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1194         }
1195
1196         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1197
1198         for (i = 0; i < PQntuples(res); i++)
1199         {
1200                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1201         }
1202
1203         PQclear(res);
1204         destroyPQExpBuffer(query);
1205 }
1206
1207 /*
1208  * selectDumpableNamespace: policy-setting subroutine
1209  *              Mark a namespace as to be dumped or not
1210  */
1211 static void
1212 selectDumpableNamespace(NamespaceInfo *nsinfo)
1213 {
1214         /*
1215          * If specific tables are being dumped, do not dump any complete
1216          * namespaces. If specific namespaces are being dumped, dump just those
1217          * namespaces. Otherwise, dump all non-system namespaces.
1218          */
1219         if (table_include_oids.head != NULL)
1220                 nsinfo->dobj.dump = false;
1221         else if (schema_include_oids.head != NULL)
1222                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1223                                                                                                    nsinfo->dobj.catId.oid);
1224         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1225                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1226                 nsinfo->dobj.dump = false;
1227         else
1228                 nsinfo->dobj.dump = true;
1229
1230         /*
1231          * In any case, a namespace can be excluded by an exclusion switch
1232          */
1233         if (nsinfo->dobj.dump &&
1234                 simple_oid_list_member(&schema_exclude_oids,
1235                                                            nsinfo->dobj.catId.oid))
1236                 nsinfo->dobj.dump = false;
1237 }
1238
1239 /*
1240  * selectDumpableTable: policy-setting subroutine
1241  *              Mark a table as to be dumped or not
1242  */
1243 static void
1244 selectDumpableTable(TableInfo *tbinfo)
1245 {
1246         /*
1247          * If specific tables are being dumped, dump just those tables; else, dump
1248          * according to the parent namespace's dump flag.
1249          */
1250         if (table_include_oids.head != NULL)
1251                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1252                                                                                                    tbinfo->dobj.catId.oid);
1253         else
1254                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1255
1256         /*
1257          * In any case, a table can be excluded by an exclusion switch
1258          */
1259         if (tbinfo->dobj.dump &&
1260                 simple_oid_list_member(&table_exclude_oids,
1261                                                            tbinfo->dobj.catId.oid))
1262                 tbinfo->dobj.dump = false;
1263 }
1264
1265 /*
1266  * selectDumpableType: policy-setting subroutine
1267  *              Mark a type as to be dumped or not
1268  *
1269  * If it's a table's rowtype or an autogenerated array type, we also apply a
1270  * special type code to facilitate sorting into the desired order.      (We don't
1271  * want to consider those to be ordinary types because that would bring tables
1272  * up into the datatype part of the dump order.)  We still set the object's
1273  * dump flag; that's not going to cause the dummy type to be dumped, but we
1274  * need it so that casts involving such types will be dumped correctly -- see
1275  * dumpCast.  This means the flag should be set the same as for the underlying
1276  * object (the table or base type).
1277  */
1278 static void
1279 selectDumpableType(TypeInfo *tyinfo)
1280 {
1281         /* skip complex types, except for standalone composite types */
1282         if (OidIsValid(tyinfo->typrelid) &&
1283                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1284         {
1285                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1286
1287                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1288                 if (tytable != NULL)
1289                         tyinfo->dobj.dump = tytable->dobj.dump;
1290                 else
1291                         tyinfo->dobj.dump = false;
1292                 return;
1293         }
1294
1295         /* skip auto-generated array types */
1296         if (tyinfo->isArray)
1297         {
1298                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1299
1300                 /*
1301                  * Fall through to set the dump flag; we assume that the subsequent
1302                  * rules will do the same thing as they would for the array's base
1303                  * type.  (We cannot reliably look up the base type here, since
1304                  * getTypes may not have processed it yet.)
1305                  */
1306         }
1307
1308         /* dump only types in dumpable namespaces */
1309         if (!tyinfo->dobj.namespace->dobj.dump)
1310                 tyinfo->dobj.dump = false;
1311
1312         /* skip undefined placeholder types */
1313         else if (!tyinfo->isDefined)
1314                 tyinfo->dobj.dump = false;
1315
1316         else
1317                 tyinfo->dobj.dump = true;
1318 }
1319
1320 /*
1321  * selectDumpableDefaultACL: policy-setting subroutine
1322  *              Mark a default ACL as to be dumped or not
1323  *
1324  * For per-schema default ACLs, dump if the schema is to be dumped.
1325  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1326  * and aclsSkip are checked separately.
1327  */
1328 static void
1329 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1330 {
1331         if (dinfo->dobj.namespace)
1332                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1333         else
1334                 dinfo->dobj.dump = include_everything;
1335 }
1336
1337 /*
1338  * selectDumpableExtension: policy-setting subroutine
1339  *              Mark an extension as to be dumped or not
1340  *
1341  * Normally, we dump all extensions, or none of them if include_everything
1342  * is false (i.e., a --schema or --table switch was given).  However, in
1343  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1344  * assume those will already be installed in the target database.  We identify
1345  * such extensions by their having OIDs in the range reserved for initdb.
1346  */
1347 static void
1348 selectDumpableExtension(ExtensionInfo *extinfo)
1349 {
1350         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1351                 extinfo->dobj.dump = false;
1352         else
1353                 extinfo->dobj.dump = include_everything;
1354 }
1355
1356 /*
1357  * selectDumpableObject: policy-setting subroutine
1358  *              Mark a generic dumpable object as to be dumped or not
1359  *
1360  * Use this only for object types without a special-case routine above.
1361  */
1362 static void
1363 selectDumpableObject(DumpableObject *dobj)
1364 {
1365         /*
1366          * Default policy is to dump if parent namespace is dumpable, or always
1367          * for non-namespace-associated items.
1368          */
1369         if (dobj->namespace)
1370                 dobj->dump = dobj->namespace->dobj.dump;
1371         else
1372                 dobj->dump = true;
1373 }
1374
1375 /*
1376  *      Dump a table's contents for loading using the COPY command
1377  *      - this routine is called by the Archiver when it wants the table
1378  *        to be dumped.
1379  */
1380
1381 static int
1382 dumpTableData_copy(Archive *fout, void *dcontext)
1383 {
1384         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1385         TableInfo  *tbinfo = tdinfo->tdtable;
1386         const char *classname = tbinfo->dobj.name;
1387         const bool      hasoids = tbinfo->hasoids;
1388         const bool      oids = tdinfo->oids;
1389         PQExpBuffer q = createPQExpBuffer();
1390
1391         /*
1392          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1393          * which uses it already.
1394          */
1395         PQExpBuffer clistBuf = createPQExpBuffer();
1396         PGconn     *conn = GetConnection(fout);
1397         PGresult   *res;
1398         int                     ret;
1399         char       *copybuf;
1400         const char *column_list;
1401
1402         if (g_verbose)
1403                 write_msg(NULL, "dumping contents of table %s\n", classname);
1404
1405         /*
1406          * Make sure we are in proper schema.  We will qualify the table name
1407          * below anyway (in case its name conflicts with a pg_catalog table); but
1408          * this ensures reproducible results in case the table contains regproc,
1409          * regclass, etc columns.
1410          */
1411         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1412
1413         /*
1414          * If possible, specify the column list explicitly so that we have no
1415          * possibility of retrieving data in the wrong column order.  (The default
1416          * column ordering of COPY will not be what we want in certain corner
1417          * cases involving ADD COLUMN and inheritance.)
1418          */
1419         if (fout->remoteVersion >= 70300)
1420                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1421         else
1422                 column_list = "";               /* can't select columns in COPY */
1423
1424         if (oids && hasoids)
1425         {
1426                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1427                                                   fmtQualifiedId(fout->remoteVersion,
1428                                                                                  tbinfo->dobj.namespace->dobj.name,
1429                                                                                  classname),
1430                                                   column_list);
1431         }
1432         else if (tdinfo->filtercond)
1433         {
1434                 /* Note: this syntax is only supported in 8.2 and up */
1435                 appendPQExpBufferStr(q, "COPY (SELECT ");
1436                 /* klugery to get rid of parens in column list */
1437                 if (strlen(column_list) > 2)
1438                 {
1439                         appendPQExpBufferStr(q, column_list + 1);
1440                         q->data[q->len - 1] = ' ';
1441                 }
1442                 else
1443                         appendPQExpBufferStr(q, "* ");
1444                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1445                                                   fmtQualifiedId(fout->remoteVersion,
1446                                                                                  tbinfo->dobj.namespace->dobj.name,
1447                                                                                  classname),
1448                                                   tdinfo->filtercond);
1449         }
1450         else
1451         {
1452                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1453                                                   fmtQualifiedId(fout->remoteVersion,
1454                                                                                  tbinfo->dobj.namespace->dobj.name,
1455                                                                                  classname),
1456                                                   column_list);
1457         }
1458         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1459         PQclear(res);
1460         destroyPQExpBuffer(clistBuf);
1461
1462         for (;;)
1463         {
1464                 ret = PQgetCopyData(conn, &copybuf, 0);
1465
1466                 if (ret < 0)
1467                         break;                          /* done or error */
1468
1469                 if (copybuf)
1470                 {
1471                         WriteData(fout, copybuf, ret);
1472                         PQfreemem(copybuf);
1473                 }
1474
1475                 /* ----------
1476                  * THROTTLE:
1477                  *
1478                  * There was considerable discussion in late July, 2000 regarding
1479                  * slowing down pg_dump when backing up large tables. Users with both
1480                  * slow & fast (multi-processor) machines experienced performance
1481                  * degradation when doing a backup.
1482                  *
1483                  * Initial attempts based on sleeping for a number of ms for each ms
1484                  * of work were deemed too complex, then a simple 'sleep in each loop'
1485                  * implementation was suggested. The latter failed because the loop
1486                  * was too tight. Finally, the following was implemented:
1487                  *
1488                  * If throttle is non-zero, then
1489                  *              See how long since the last sleep.
1490                  *              Work out how long to sleep (based on ratio).
1491                  *              If sleep is more than 100ms, then
1492                  *                      sleep
1493                  *                      reset timer
1494                  *              EndIf
1495                  * EndIf
1496                  *
1497                  * where the throttle value was the number of ms to sleep per ms of
1498                  * work. The calculation was done in each loop.
1499                  *
1500                  * Most of the hard work is done in the backend, and this solution
1501                  * still did not work particularly well: on slow machines, the ratio
1502                  * was 50:1, and on medium paced machines, 1:1, and on fast
1503                  * multi-processor machines, it had little or no effect, for reasons
1504                  * that were unclear.
1505                  *
1506                  * Further discussion ensued, and the proposal was dropped.
1507                  *
1508                  * For those people who want this feature, it can be implemented using
1509                  * gettimeofday in each loop, calculating the time since last sleep,
1510                  * multiplying that by the sleep ratio, then if the result is more
1511                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1512                  * function to sleep for a subsecond period ie.
1513                  *
1514                  * select(0, NULL, NULL, NULL, &tvi);
1515                  *
1516                  * This will return after the interval specified in the structure tvi.
1517                  * Finally, call gettimeofday again to save the 'last sleep time'.
1518                  * ----------
1519                  */
1520         }
1521         archprintf(fout, "\\.\n\n\n");
1522
1523         if (ret == -2)
1524         {
1525                 /* copy data transfer failed */
1526                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1527                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1528                 write_msg(NULL, "The command was: %s\n", q->data);
1529                 exit_nicely(1);
1530         }
1531
1532         /* Check command status and return to normal libpq state */
1533         res = PQgetResult(conn);
1534         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1535         {
1536                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1537                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1538                 write_msg(NULL, "The command was: %s\n", q->data);
1539                 exit_nicely(1);
1540         }
1541         PQclear(res);
1542
1543         destroyPQExpBuffer(q);
1544         return 1;
1545 }
1546
1547 /*
1548  * Dump table data using INSERT commands.
1549  *
1550  * Caution: when we restore from an archive file direct to database, the
1551  * INSERT commands emitted by this function have to be parsed by
1552  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1553  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1554  */
1555 static int
1556 dumpTableData_insert(Archive *fout, void *dcontext)
1557 {
1558         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1559         TableInfo  *tbinfo = tdinfo->tdtable;
1560         const char *classname = tbinfo->dobj.name;
1561         PQExpBuffer q = createPQExpBuffer();
1562         PQExpBuffer insertStmt = NULL;
1563         PGresult   *res;
1564         int                     tuple;
1565         int                     nfields;
1566         int                     field;
1567
1568         /*
1569          * Make sure we are in proper schema.  We will qualify the table name
1570          * below anyway (in case its name conflicts with a pg_catalog table); but
1571          * this ensures reproducible results in case the table contains regproc,
1572          * regclass, etc columns.
1573          */
1574         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1575
1576         if (fout->remoteVersion >= 70100)
1577         {
1578                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1579                                                   "SELECT * FROM ONLY %s",
1580                                                   fmtQualifiedId(fout->remoteVersion,
1581                                                                                  tbinfo->dobj.namespace->dobj.name,
1582                                                                                  classname));
1583         }
1584         else
1585         {
1586                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1587                                                   "SELECT * FROM %s",
1588                                                   fmtQualifiedId(fout->remoteVersion,
1589                                                                                  tbinfo->dobj.namespace->dobj.name,
1590                                                                                  classname));
1591         }
1592         if (tdinfo->filtercond)
1593                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1594
1595         ExecuteSqlStatement(fout, q->data);
1596
1597         while (1)
1598         {
1599                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1600                                                           PGRES_TUPLES_OK);
1601                 nfields = PQnfields(res);
1602                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1603                 {
1604                         /*
1605                          * First time through, we build as much of the INSERT statement as
1606                          * possible in "insertStmt", which we can then just print for each
1607                          * line. If the table happens to have zero columns then this will
1608                          * be a complete statement, otherwise it will end in "VALUES(" and
1609                          * be ready to have the row's column values appended.
1610                          */
1611                         if (insertStmt == NULL)
1612                         {
1613                                 insertStmt = createPQExpBuffer();
1614                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1615                                                                   fmtId(classname));
1616
1617                                 /* corner case for zero-column table */
1618                                 if (nfields == 0)
1619                                 {
1620                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1621                                 }
1622                                 else
1623                                 {
1624                                         /* append the list of column names if required */
1625                                         if (column_inserts)
1626                                         {
1627                                                 appendPQExpBufferStr(insertStmt, "(");
1628                                                 for (field = 0; field < nfields; field++)
1629                                                 {
1630                                                         if (field > 0)
1631                                                                 appendPQExpBufferStr(insertStmt, ", ");
1632                                                         appendPQExpBufferStr(insertStmt,
1633                                                                                                  fmtId(PQfname(res, field)));
1634                                                 }
1635                                                 appendPQExpBufferStr(insertStmt, ") ");
1636                                         }
1637
1638                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1639                                 }
1640                         }
1641
1642                         archputs(insertStmt->data, fout);
1643
1644                         /* if it is zero-column table then we're done */
1645                         if (nfields == 0)
1646                                 continue;
1647
1648                         for (field = 0; field < nfields; field++)
1649                         {
1650                                 if (field > 0)
1651                                         archputs(", ", fout);
1652                                 if (PQgetisnull(res, tuple, field))
1653                                 {
1654                                         archputs("NULL", fout);
1655                                         continue;
1656                                 }
1657
1658                                 /* XXX This code is partially duplicated in ruleutils.c */
1659                                 switch (PQftype(res, field))
1660                                 {
1661                                         case INT2OID:
1662                                         case INT4OID:
1663                                         case INT8OID:
1664                                         case OIDOID:
1665                                         case FLOAT4OID:
1666                                         case FLOAT8OID:
1667                                         case NUMERICOID:
1668                                                 {
1669                                                         /*
1670                                                          * These types are printed without quotes unless
1671                                                          * they contain values that aren't accepted by the
1672                                                          * scanner unquoted (e.g., 'NaN').      Note that
1673                                                          * strtod() and friends might accept NaN, so we
1674                                                          * can't use that to test.
1675                                                          *
1676                                                          * In reality we only need to defend against
1677                                                          * infinity and NaN, so we need not get too crazy
1678                                                          * about pattern matching here.
1679                                                          */
1680                                                         const char *s = PQgetvalue(res, tuple, field);
1681
1682                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1683                                                                 archputs(s, fout);
1684                                                         else
1685                                                                 archprintf(fout, "'%s'", s);
1686                                                 }
1687                                                 break;
1688
1689                                         case BITOID:
1690                                         case VARBITOID:
1691                                                 archprintf(fout, "B'%s'",
1692                                                                    PQgetvalue(res, tuple, field));
1693                                                 break;
1694
1695                                         case BOOLOID:
1696                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1697                                                         archputs("true", fout);
1698                                                 else
1699                                                         archputs("false", fout);
1700                                                 break;
1701
1702                                         default:
1703                                                 /* All other types are printed as string literals. */
1704                                                 resetPQExpBuffer(q);
1705                                                 appendStringLiteralAH(q,
1706                                                                                           PQgetvalue(res, tuple, field),
1707                                                                                           fout);
1708                                                 archputs(q->data, fout);
1709                                                 break;
1710                                 }
1711                         }
1712                         archputs(");\n", fout);
1713                 }
1714
1715                 if (PQntuples(res) <= 0)
1716                 {
1717                         PQclear(res);
1718                         break;
1719                 }
1720                 PQclear(res);
1721         }
1722
1723         archputs("\n\n", fout);
1724
1725         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1726
1727         destroyPQExpBuffer(q);
1728         if (insertStmt != NULL)
1729                 destroyPQExpBuffer(insertStmt);
1730
1731         return 1;
1732 }
1733
1734
1735 /*
1736  * dumpTableData -
1737  *        dump the contents of a single table
1738  *
1739  * Actually, this just makes an ArchiveEntry for the table contents.
1740  */
1741 static void
1742 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1743 {
1744         TableInfo  *tbinfo = tdinfo->tdtable;
1745         PQExpBuffer copyBuf = createPQExpBuffer();
1746         PQExpBuffer clistBuf = createPQExpBuffer();
1747         DataDumperPtr dumpFn;
1748         char       *copyStmt;
1749
1750         if (!dump_inserts)
1751         {
1752                 /* Dump/restore using COPY */
1753                 dumpFn = dumpTableData_copy;
1754                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1755                 appendPQExpBuffer(copyBuf, "COPY %s ",
1756                                                   fmtId(tbinfo->dobj.name));
1757                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1758                                                   fmtCopyColumnList(tbinfo, clistBuf),
1759                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1760                 copyStmt = copyBuf->data;
1761         }
1762         else
1763         {
1764                 /* Restore using INSERT */
1765                 dumpFn = dumpTableData_insert;
1766                 copyStmt = NULL;
1767         }
1768
1769         /*
1770          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1771          * dependency on its table as "special" and pass it to ArchiveEntry now.
1772          * See comments for BuildArchiveDependencies.
1773          */
1774         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1775                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1776                                  NULL, tbinfo->rolname,
1777                                  false, "TABLE DATA", SECTION_DATA,
1778                                  "", "", copyStmt,
1779                                  &(tbinfo->dobj.dumpId), 1,
1780                                  dumpFn, tdinfo);
1781
1782         destroyPQExpBuffer(copyBuf);
1783         destroyPQExpBuffer(clistBuf);
1784 }
1785
1786 /*
1787  * refreshMatViewData -
1788  *        load or refresh the contents of a single materialized view
1789  *
1790  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1791  * statement.
1792  */
1793 static void
1794 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1795 {
1796         TableInfo  *tbinfo = tdinfo->tdtable;
1797         PQExpBuffer q;
1798
1799         /* If the materialized view is not flagged as populated, skip this. */
1800         if (!tbinfo->relispopulated)
1801                 return;
1802
1803         q = createPQExpBuffer();
1804
1805         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1806                                           fmtId(tbinfo->dobj.name));
1807
1808         ArchiveEntry(fout,
1809                                  tdinfo->dobj.catId,    /* catalog ID */
1810                                  tdinfo->dobj.dumpId,   /* dump ID */
1811                                  tbinfo->dobj.name,             /* Name */
1812                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1813                                  NULL,                  /* Tablespace */
1814                                  tbinfo->rolname,               /* Owner */
1815                                  false,                 /* with oids */
1816                                  "MATERIALIZED VIEW DATA",              /* Desc */
1817                                  SECTION_POST_DATA,             /* Section */
1818                                  q->data,               /* Create */
1819                                  "",                    /* Del */
1820                                  NULL,                  /* Copy */
1821                                  tdinfo->dobj.dependencies,             /* Deps */
1822                                  tdinfo->dobj.nDeps,    /* # Deps */
1823                                  NULL,                  /* Dumper */
1824                                  NULL);                 /* Dumper Arg */
1825
1826         destroyPQExpBuffer(q);
1827 }
1828
1829 /*
1830  * getTableData -
1831  *        set up dumpable objects representing the contents of tables
1832  */
1833 static void
1834 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1835 {
1836         int                     i;
1837
1838         for (i = 0; i < numTables; i++)
1839         {
1840                 if (tblinfo[i].dobj.dump)
1841                         makeTableDataInfo(&(tblinfo[i]), oids);
1842         }
1843 }
1844
1845 /*
1846  * Make a dumpable object for the data of this specific table
1847  *
1848  * Note: we make a TableDataInfo if and only if we are going to dump the
1849  * table data; the "dump" flag in such objects isn't used.
1850  */
1851 static void
1852 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1853 {
1854         TableDataInfo *tdinfo;
1855
1856         /*
1857          * Nothing to do if we already decided to dump the table.  This will
1858          * happen for "config" tables.
1859          */
1860         if (tbinfo->dataObj != NULL)
1861                 return;
1862
1863         /* Skip VIEWs (no data to dump) */
1864         if (tbinfo->relkind == RELKIND_VIEW)
1865                 return;
1866         /* Skip FOREIGN TABLEs (no data to dump) */
1867         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1868                 return;
1869
1870         /* Don't dump data in unlogged tables, if so requested */
1871         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1872                 no_unlogged_table_data)
1873                 return;
1874
1875         /* Check that the data is not explicitly excluded */
1876         if (simple_oid_list_member(&tabledata_exclude_oids,
1877                                                            tbinfo->dobj.catId.oid))
1878                 return;
1879
1880         /* OK, let's dump it */
1881         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1882
1883         if (tbinfo->relkind == RELKIND_MATVIEW)
1884                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1885         else
1886                 tdinfo->dobj.objType = DO_TABLE_DATA;
1887
1888         /*
1889          * Note: use tableoid 0 so that this object won't be mistaken for
1890          * something that pg_depend entries apply to.
1891          */
1892         tdinfo->dobj.catId.tableoid = 0;
1893         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1894         AssignDumpId(&tdinfo->dobj);
1895         tdinfo->dobj.name = tbinfo->dobj.name;
1896         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1897         tdinfo->tdtable = tbinfo;
1898         tdinfo->oids = oids;
1899         tdinfo->filtercond = NULL;      /* might get set later */
1900         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1901
1902         tbinfo->dataObj = tdinfo;
1903 }
1904
1905 /*
1906  * The refresh for a materialized view must be dependent on the refresh for
1907  * any materialized view that this one is dependent on.
1908  *
1909  * This must be called after all the objects are created, but before they are
1910  * sorted.
1911  */
1912 static void
1913 buildMatViewRefreshDependencies(Archive *fout)
1914 {
1915         PQExpBuffer query;
1916         PGresult   *res;
1917         int                     ntups,
1918                                 i;
1919         int                     i_classid,
1920                                 i_objid,
1921                                 i_refobjid;
1922
1923         /* No Mat Views before 9.3. */
1924         if (fout->remoteVersion < 90300)
1925                 return;
1926
1927         /* Make sure we are in proper schema */
1928         selectSourceSchema(fout, "pg_catalog");
1929
1930         query = createPQExpBuffer();
1931
1932         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
1933                                           "( "
1934                                         "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
1935                                           "FROM pg_depend d1 "
1936                                           "JOIN pg_class c1 ON c1.oid = d1.objid "
1937                                           "AND c1.relkind = 'm' "
1938                                           "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
1939                                   "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
1940                                           "AND d2.objid = r1.oid "
1941                                           "AND d2.refobjid <> d1.objid "
1942                                           "JOIN pg_class c2 ON c2.oid = d2.refobjid "
1943                                           "AND c2.relkind IN ('m','v') "
1944                                           "WHERE d1.classid = 'pg_class'::regclass "
1945                                           "UNION "
1946                                           "SELECT w.objid, d3.refobjid, c3.relkind "
1947                                           "FROM w "
1948                                           "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
1949                                   "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
1950                                           "AND d3.objid = r3.oid "
1951                                           "AND d3.refobjid <> w.refobjid "
1952                                           "JOIN pg_class c3 ON c3.oid = d3.refobjid "
1953                                           "AND c3.relkind IN ('m','v') "
1954                                           ") "
1955                           "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
1956                                           "FROM w "
1957                                           "WHERE refrelkind = 'm'");
1958
1959         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1960
1961         ntups = PQntuples(res);
1962
1963         i_classid = PQfnumber(res, "classid");
1964         i_objid = PQfnumber(res, "objid");
1965         i_refobjid = PQfnumber(res, "refobjid");
1966
1967         for (i = 0; i < ntups; i++)
1968         {
1969                 CatalogId       objId;
1970                 CatalogId       refobjId;
1971                 DumpableObject *dobj;
1972                 DumpableObject *refdobj;
1973                 TableInfo  *tbinfo;
1974                 TableInfo  *reftbinfo;
1975
1976                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1977                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1978                 refobjId.tableoid = objId.tableoid;
1979                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1980
1981                 dobj = findObjectByCatalogId(objId);
1982                 if (dobj == NULL)
1983                         continue;
1984
1985                 Assert(dobj->objType == DO_TABLE);
1986                 tbinfo = (TableInfo *) dobj;
1987                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1988                 dobj = (DumpableObject *) tbinfo->dataObj;
1989                 if (dobj == NULL)
1990                         continue;
1991                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
1992
1993                 refdobj = findObjectByCatalogId(refobjId);
1994                 if (refdobj == NULL)
1995                         continue;
1996
1997                 Assert(refdobj->objType == DO_TABLE);
1998                 reftbinfo = (TableInfo *) refdobj;
1999                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2000                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2001                 if (refdobj == NULL)
2002                         continue;
2003                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2004
2005                 addObjectDependency(dobj, refdobj->dumpId);
2006
2007                 if (!reftbinfo->relispopulated)
2008                         tbinfo->relispopulated = false;
2009         }
2010
2011         PQclear(res);
2012
2013         destroyPQExpBuffer(query);
2014 }
2015
2016 /*
2017  * getTableDataFKConstraints -
2018  *        add dump-order dependencies reflecting foreign key constraints
2019  *
2020  * This code is executed only in a data-only dump --- in schema+data dumps
2021  * we handle foreign key issues by not creating the FK constraints until
2022  * after the data is loaded.  In a data-only dump, however, we want to
2023  * order the table data objects in such a way that a table's referenced
2024  * tables are restored first.  (In the presence of circular references or
2025  * self-references this may be impossible; we'll detect and complain about
2026  * that during the dependency sorting step.)
2027  */
2028 static void
2029 getTableDataFKConstraints(void)
2030 {
2031         DumpableObject **dobjs;
2032         int                     numObjs;
2033         int                     i;
2034
2035         /* Search through all the dumpable objects for FK constraints */
2036         getDumpableObjects(&dobjs, &numObjs);
2037         for (i = 0; i < numObjs; i++)
2038         {
2039                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2040                 {
2041                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2042                         TableInfo  *ftable;
2043
2044                         /* Not interesting unless both tables are to be dumped */
2045                         if (cinfo->contable == NULL ||
2046                                 cinfo->contable->dataObj == NULL)
2047                                 continue;
2048                         ftable = findTableByOid(cinfo->confrelid);
2049                         if (ftable == NULL ||
2050                                 ftable->dataObj == NULL)
2051                                 continue;
2052
2053                         /*
2054                          * Okay, make referencing table's TABLE_DATA object depend on the
2055                          * referenced table's TABLE_DATA object.
2056                          */
2057                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2058                                                                 ftable->dataObj->dobj.dumpId);
2059                 }
2060         }
2061         free(dobjs);
2062 }
2063
2064
2065 /*
2066  * guessConstraintInheritance:
2067  *      In pre-8.4 databases, we can't tell for certain which constraints
2068  *      are inherited.  We assume a CHECK constraint is inherited if its name
2069  *      matches the name of any constraint in the parent.  Originally this code
2070  *      tried to compare the expression texts, but that can fail for various
2071  *      reasons --- for example, if the parent and child tables are in different
2072  *      schemas, reverse-listing of function calls may produce different text
2073  *      (schema-qualified or not) depending on search path.
2074  *
2075  *      In 8.4 and up we can rely on the conislocal field to decide which
2076  *      constraints must be dumped; much safer.
2077  *
2078  *      This function assumes all conislocal flags were initialized to TRUE.
2079  *      It clears the flag on anything that seems to be inherited.
2080  */
2081 static void
2082 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2083 {
2084         int                     i,
2085                                 j,
2086                                 k;
2087
2088         for (i = 0; i < numTables; i++)
2089         {
2090                 TableInfo  *tbinfo = &(tblinfo[i]);
2091                 int                     numParents;
2092                 TableInfo **parents;
2093                 TableInfo  *parent;
2094
2095                 /* Sequences and views never have parents */
2096                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2097                         tbinfo->relkind == RELKIND_VIEW)
2098                         continue;
2099
2100                 /* Don't bother computing anything for non-target tables, either */
2101                 if (!tbinfo->dobj.dump)
2102                         continue;
2103
2104                 numParents = tbinfo->numParents;
2105                 parents = tbinfo->parents;
2106
2107                 if (numParents == 0)
2108                         continue;                       /* nothing to see here, move along */
2109
2110                 /* scan for inherited CHECK constraints */
2111                 for (j = 0; j < tbinfo->ncheck; j++)
2112                 {
2113                         ConstraintInfo *constr;
2114
2115                         constr = &(tbinfo->checkexprs[j]);
2116
2117                         for (k = 0; k < numParents; k++)
2118                         {
2119                                 int                     l;
2120
2121                                 parent = parents[k];
2122                                 for (l = 0; l < parent->ncheck; l++)
2123                                 {
2124                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2125
2126                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2127                                         {
2128                                                 constr->conislocal = false;
2129                                                 break;
2130                                         }
2131                                 }
2132                                 if (!constr->conislocal)
2133                                         break;
2134                         }
2135                 }
2136         }
2137 }
2138
2139
2140 /*
2141  * dumpDatabase:
2142  *      dump the database definition
2143  */
2144 static void
2145 dumpDatabase(Archive *fout)
2146 {
2147         PQExpBuffer dbQry = createPQExpBuffer();
2148         PQExpBuffer delQry = createPQExpBuffer();
2149         PQExpBuffer creaQry = createPQExpBuffer();
2150         PGconn     *conn = GetConnection(fout);
2151         PGresult   *res;
2152         int                     i_tableoid,
2153                                 i_oid,
2154                                 i_dba,
2155                                 i_encoding,
2156                                 i_collate,
2157                                 i_ctype,
2158                                 i_frozenxid,
2159                                 i_tablespace;
2160         CatalogId       dbCatId;
2161         DumpId          dbDumpId;
2162         const char *datname,
2163                            *dba,
2164                            *encoding,
2165                            *collate,
2166                            *ctype,
2167                            *tablespace;
2168         uint32          frozenxid;
2169
2170         datname = PQdb(conn);
2171
2172         if (g_verbose)
2173                 write_msg(NULL, "saving database definition\n");
2174
2175         /* Make sure we are in proper schema */
2176         selectSourceSchema(fout, "pg_catalog");
2177
2178         /* Get the database owner and parameters from pg_database */
2179         if (fout->remoteVersion >= 80400)
2180         {
2181                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2182                                                   "(%s datdba) AS dba, "
2183                                                   "pg_encoding_to_char(encoding) AS encoding, "
2184                                                   "datcollate, datctype, datfrozenxid, "
2185                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2186                                           "shobj_description(oid, 'pg_database') AS description "
2187
2188                                                   "FROM pg_database "
2189                                                   "WHERE datname = ",
2190                                                   username_subquery);
2191                 appendStringLiteralAH(dbQry, datname, fout);
2192         }
2193         else if (fout->remoteVersion >= 80200)
2194         {
2195                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2196                                                   "(%s datdba) AS dba, "
2197                                                   "pg_encoding_to_char(encoding) AS encoding, "
2198                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2199                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2200                                           "shobj_description(oid, 'pg_database') AS description "
2201
2202                                                   "FROM pg_database "
2203                                                   "WHERE datname = ",
2204                                                   username_subquery);
2205                 appendStringLiteralAH(dbQry, datname, fout);
2206         }
2207         else if (fout->remoteVersion >= 80000)
2208         {
2209                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2210                                                   "(%s datdba) AS dba, "
2211                                                   "pg_encoding_to_char(encoding) AS encoding, "
2212                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2213                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2214                                                   "FROM pg_database "
2215                                                   "WHERE datname = ",
2216                                                   username_subquery);
2217                 appendStringLiteralAH(dbQry, datname, fout);
2218         }
2219         else if (fout->remoteVersion >= 70100)
2220         {
2221                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2222                                                   "(%s datdba) AS dba, "
2223                                                   "pg_encoding_to_char(encoding) AS encoding, "
2224                                                   "NULL AS datcollate, NULL AS datctype, "
2225                                                   "0 AS datfrozenxid, "
2226                                                   "NULL AS tablespace "
2227                                                   "FROM pg_database "
2228                                                   "WHERE datname = ",
2229                                                   username_subquery);
2230                 appendStringLiteralAH(dbQry, datname, fout);
2231         }
2232         else
2233         {
2234                 appendPQExpBuffer(dbQry, "SELECT "
2235                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2236                                                   "oid, "
2237                                                   "(%s datdba) AS dba, "
2238                                                   "pg_encoding_to_char(encoding) AS encoding, "
2239                                                   "NULL AS datcollate, NULL AS datctype, "
2240                                                   "0 AS datfrozenxid, "
2241                                                   "NULL AS tablespace "
2242                                                   "FROM pg_database "
2243                                                   "WHERE datname = ",
2244                                                   username_subquery);
2245                 appendStringLiteralAH(dbQry, datname, fout);
2246         }
2247
2248         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2249
2250         i_tableoid = PQfnumber(res, "tableoid");
2251         i_oid = PQfnumber(res, "oid");
2252         i_dba = PQfnumber(res, "dba");
2253         i_encoding = PQfnumber(res, "encoding");
2254         i_collate = PQfnumber(res, "datcollate");
2255         i_ctype = PQfnumber(res, "datctype");
2256         i_frozenxid = PQfnumber(res, "datfrozenxid");
2257         i_tablespace = PQfnumber(res, "tablespace");
2258
2259         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2260         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2261         dba = PQgetvalue(res, 0, i_dba);
2262         encoding = PQgetvalue(res, 0, i_encoding);
2263         collate = PQgetvalue(res, 0, i_collate);
2264         ctype = PQgetvalue(res, 0, i_ctype);
2265         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2266         tablespace = PQgetvalue(res, 0, i_tablespace);
2267
2268         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2269                                           fmtId(datname));
2270         if (strlen(encoding) > 0)
2271         {
2272                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2273                 appendStringLiteralAH(creaQry, encoding, fout);
2274         }
2275         if (strlen(collate) > 0)
2276         {
2277                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2278                 appendStringLiteralAH(creaQry, collate, fout);
2279         }
2280         if (strlen(ctype) > 0)
2281         {
2282                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2283                 appendStringLiteralAH(creaQry, ctype, fout);
2284         }
2285         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2286                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2287                                                   fmtId(tablespace));
2288         appendPQExpBufferStr(creaQry, ";\n");
2289
2290         if (binary_upgrade)
2291         {
2292                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
2293                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2294                                                   "SET datfrozenxid = '%u'\n"
2295                                                   "WHERE        datname = ",
2296                                                   frozenxid);
2297                 appendStringLiteralAH(creaQry, datname, fout);
2298                 appendPQExpBufferStr(creaQry, ";\n");
2299
2300         }
2301
2302         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2303                                           fmtId(datname));
2304
2305         dbDumpId = createDumpId();
2306
2307         ArchiveEntry(fout,
2308                                  dbCatId,               /* catalog ID */
2309                                  dbDumpId,              /* dump ID */
2310                                  datname,               /* Name */
2311                                  NULL,                  /* Namespace */
2312                                  NULL,                  /* Tablespace */
2313                                  dba,                   /* Owner */
2314                                  false,                 /* with oids */
2315                                  "DATABASE",    /* Desc */
2316                                  SECTION_PRE_DATA,              /* Section */
2317                                  creaQry->data, /* Create */
2318                                  delQry->data,  /* Del */
2319                                  NULL,                  /* Copy */
2320                                  NULL,                  /* Deps */
2321                                  0,                             /* # Deps */
2322                                  NULL,                  /* Dumper */
2323                                  NULL);                 /* Dumper Arg */
2324
2325         /*
2326          * pg_largeobject and pg_largeobject_metadata come from the old system
2327          * intact, so set their relfrozenxids.
2328          */
2329         if (binary_upgrade)
2330         {
2331                 PGresult   *lo_res;
2332                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2333                 PQExpBuffer loOutQry = createPQExpBuffer();
2334                 int                     i_relfrozenxid;
2335
2336                 /*
2337                  * pg_largeobject
2338                  */
2339                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2340                                                   "FROM pg_catalog.pg_class\n"
2341                                                   "WHERE oid = %u;\n",
2342                                                   LargeObjectRelationId);
2343
2344                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2345
2346                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2347
2348                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2349                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2350                                                   "SET relfrozenxid = '%u'\n"
2351                                                   "WHERE oid = %u;\n",
2352                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2353                                                   LargeObjectRelationId);
2354                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2355                                          "pg_largeobject", NULL, NULL, "",
2356                                          false, "pg_largeobject", SECTION_PRE_DATA,
2357                                          loOutQry->data, "", NULL,
2358                                          NULL, 0,
2359                                          NULL, NULL);
2360
2361                 PQclear(lo_res);
2362
2363                 /*
2364                  * pg_largeobject_metadata
2365                  */
2366                 if (fout->remoteVersion >= 90000)
2367                 {
2368                         resetPQExpBuffer(loFrozenQry);
2369                         resetPQExpBuffer(loOutQry);
2370
2371                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2372                                                           "FROM pg_catalog.pg_class\n"
2373                                                           "WHERE oid = %u;\n",
2374                                                           LargeObjectMetadataRelationId);
2375
2376                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2377
2378                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2379
2380                         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2381                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2382                                                           "SET relfrozenxid = '%u'\n"
2383                                                           "WHERE oid = %u;\n",
2384                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2385                                                           LargeObjectMetadataRelationId);
2386                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2387                                                  "pg_largeobject_metadata", NULL, NULL, "",
2388                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2389                                                  loOutQry->data, "", NULL,
2390                                                  NULL, 0,
2391                                                  NULL, NULL);
2392
2393                         PQclear(lo_res);
2394                 }
2395
2396                 destroyPQExpBuffer(loFrozenQry);
2397                 destroyPQExpBuffer(loOutQry);
2398         }
2399
2400         /* Dump DB comment if any */
2401         if (fout->remoteVersion >= 80200)
2402         {
2403                 /*
2404                  * 8.2 keeps comments on shared objects in a shared table, so we
2405                  * cannot use the dumpComment used for other database objects.
2406                  */
2407                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2408
2409                 if (comment && strlen(comment))
2410                 {
2411                         resetPQExpBuffer(dbQry);
2412
2413                         /*
2414                          * Generates warning when loaded into a differently-named
2415                          * database.
2416                          */
2417                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2418                         appendStringLiteralAH(dbQry, comment, fout);
2419                         appendPQExpBufferStr(dbQry, ";\n");
2420
2421                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2422                                                  dba, false, "COMMENT", SECTION_NONE,
2423                                                  dbQry->data, "", NULL,
2424                                                  &dbDumpId, 1, NULL, NULL);
2425                 }
2426         }
2427         else
2428         {
2429                 resetPQExpBuffer(dbQry);
2430                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2431                 dumpComment(fout, dbQry->data, NULL, "",
2432                                         dbCatId, 0, dbDumpId);
2433         }
2434
2435         PQclear(res);
2436
2437         /* Dump shared security label. */
2438         if (!no_security_labels && fout->remoteVersion >= 90200)
2439         {
2440                 PQExpBuffer seclabelQry = createPQExpBuffer();
2441
2442                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2443                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2444                 resetPQExpBuffer(seclabelQry);
2445                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2446                 if (strlen(seclabelQry->data))
2447                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2448                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2449                                                  seclabelQry->data, "", NULL,
2450                                                  &dbDumpId, 1, NULL, NULL);
2451                 destroyPQExpBuffer(seclabelQry);
2452         }
2453
2454         destroyPQExpBuffer(dbQry);
2455         destroyPQExpBuffer(delQry);
2456         destroyPQExpBuffer(creaQry);
2457 }
2458
2459
2460 /*
2461  * dumpEncoding: put the correct encoding into the archive
2462  */
2463 static void
2464 dumpEncoding(Archive *AH)
2465 {
2466         const char *encname = pg_encoding_to_char(AH->encoding);
2467         PQExpBuffer qry = createPQExpBuffer();
2468
2469         if (g_verbose)
2470                 write_msg(NULL, "saving encoding = %s\n", encname);
2471
2472         appendPQExpBufferStr(qry, "SET client_encoding = ");
2473         appendStringLiteralAH(qry, encname, AH);
2474         appendPQExpBufferStr(qry, ";\n");
2475
2476         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2477                                  "ENCODING", NULL, NULL, "",
2478                                  false, "ENCODING", SECTION_PRE_DATA,
2479                                  qry->data, "", NULL,
2480                                  NULL, 0,
2481                                  NULL, NULL);
2482
2483         destroyPQExpBuffer(qry);
2484 }
2485
2486
2487 /*
2488  * dumpStdStrings: put the correct escape string behavior into the archive
2489  */
2490 static void
2491 dumpStdStrings(Archive *AH)
2492 {
2493         const char *stdstrings = AH->std_strings ? "on" : "off";
2494         PQExpBuffer qry = createPQExpBuffer();
2495
2496         if (g_verbose)
2497                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2498                                   stdstrings);
2499
2500         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2501                                           stdstrings);
2502
2503         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2504                                  "STDSTRINGS", NULL, NULL, "",
2505                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2506                                  qry->data, "", NULL,
2507                                  NULL, 0,
2508                                  NULL, NULL);
2509
2510         destroyPQExpBuffer(qry);
2511 }
2512
2513
2514 /*
2515  * getBlobs:
2516  *      Collect schema-level data about large objects
2517  */
2518 static void
2519 getBlobs(Archive *fout)
2520 {
2521         PQExpBuffer blobQry = createPQExpBuffer();
2522         BlobInfo   *binfo;
2523         DumpableObject *bdata;
2524         PGresult   *res;
2525         int                     ntups;
2526         int                     i;
2527
2528         /* Verbose message */
2529         if (g_verbose)
2530                 write_msg(NULL, "reading large objects\n");
2531
2532         /* Make sure we are in proper schema */
2533         selectSourceSchema(fout, "pg_catalog");
2534
2535         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2536         if (fout->remoteVersion >= 90000)
2537                 appendPQExpBuffer(blobQry,
2538                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2539                                                   " FROM pg_largeobject_metadata",
2540                                                   username_subquery);
2541         else if (fout->remoteVersion >= 70100)
2542                 appendPQExpBufferStr(blobQry,
2543                                                          "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2544                                                          " FROM pg_largeobject");
2545         else
2546                 appendPQExpBufferStr(blobQry,
2547                                                          "SELECT oid, NULL::oid, NULL::oid"
2548                                                          " FROM pg_class WHERE relkind = 'l'");
2549
2550         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2551
2552         ntups = PQntuples(res);
2553         if (ntups > 0)
2554         {
2555                 /*
2556                  * Each large object has its own BLOB archive entry.
2557                  */
2558                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2559
2560                 for (i = 0; i < ntups; i++)
2561                 {
2562                         binfo[i].dobj.objType = DO_BLOB;
2563                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2564                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2565                         AssignDumpId(&binfo[i].dobj);
2566
2567                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2568                         if (!PQgetisnull(res, i, 1))
2569                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2570                         else
2571                                 binfo[i].rolname = "";
2572                         if (!PQgetisnull(res, i, 2))
2573                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2574                         else
2575                                 binfo[i].blobacl = NULL;
2576                 }
2577
2578                 /*
2579                  * If we have any large objects, a "BLOBS" archive entry is needed.
2580                  * This is just a placeholder for sorting; it carries no data now.
2581                  */
2582                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2583                 bdata->objType = DO_BLOB_DATA;
2584                 bdata->catId = nilCatalogId;
2585                 AssignDumpId(bdata);
2586                 bdata->name = pg_strdup("BLOBS");
2587         }
2588
2589         PQclear(res);
2590         destroyPQExpBuffer(blobQry);
2591 }
2592
2593 /*
2594  * dumpBlob
2595  *
2596  * dump the definition (metadata) of the given large object
2597  */
2598 static void
2599 dumpBlob(Archive *fout, BlobInfo *binfo)
2600 {
2601         PQExpBuffer cquery = createPQExpBuffer();
2602         PQExpBuffer dquery = createPQExpBuffer();
2603
2604         appendPQExpBuffer(cquery,
2605                                           "SELECT pg_catalog.lo_create('%s');\n",
2606                                           binfo->dobj.name);
2607
2608         appendPQExpBuffer(dquery,
2609                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2610                                           binfo->dobj.name);
2611
2612         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2613                                  binfo->dobj.name,
2614                                  NULL, NULL,
2615                                  binfo->rolname, false,
2616                                  "BLOB", SECTION_PRE_DATA,
2617                                  cquery->data, dquery->data, NULL,
2618                                  NULL, 0,
2619                                  NULL, NULL);
2620
2621         /* set up tag for comment and/or ACL */
2622         resetPQExpBuffer(cquery);
2623         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2624
2625         /* Dump comment if any */
2626         dumpComment(fout, cquery->data,
2627                                 NULL, binfo->rolname,
2628                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2629
2630         /* Dump security label if any */
2631         dumpSecLabel(fout, cquery->data,
2632                                  NULL, binfo->rolname,
2633                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2634
2635         /* Dump ACL if any */
2636         if (binfo->blobacl)
2637                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2638                                 binfo->dobj.name, NULL, cquery->data,
2639                                 NULL, binfo->rolname, binfo->blobacl);
2640
2641         destroyPQExpBuffer(cquery);
2642         destroyPQExpBuffer(dquery);
2643 }
2644
2645 /*
2646  * dumpBlobs:
2647  *      dump the data contents of all large objects
2648  */
2649 static int
2650 dumpBlobs(Archive *fout, void *arg)
2651 {
2652         const char *blobQry;
2653         const char *blobFetchQry;
2654         PGconn     *conn = GetConnection(fout);
2655         PGresult   *res;
2656         char            buf[LOBBUFSIZE];
2657         int                     ntups;
2658         int                     i;
2659         int                     cnt;
2660
2661         if (g_verbose)
2662                 write_msg(NULL, "saving large objects\n");
2663
2664         /* Make sure we are in proper schema */
2665         selectSourceSchema(fout, "pg_catalog");
2666
2667         /*
2668          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2669          * the already-in-memory dumpable objects instead...
2670          */
2671         if (fout->remoteVersion >= 90000)
2672                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2673         else if (fout->remoteVersion >= 70100)
2674                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2675         else
2676                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2677
2678         ExecuteSqlStatement(fout, blobQry);
2679
2680         /* Command to fetch from cursor */
2681         blobFetchQry = "FETCH 1000 IN bloboid";
2682
2683         do
2684         {
2685                 /* Do a fetch */
2686                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2687
2688                 /* Process the tuples, if any */
2689                 ntups = PQntuples(res);
2690                 for (i = 0; i < ntups; i++)
2691                 {
2692                         Oid                     blobOid;
2693                         int                     loFd;
2694
2695                         blobOid = atooid(PQgetvalue(res, i, 0));
2696                         /* Open the BLOB */
2697                         loFd = lo_open(conn, blobOid, INV_READ);
2698                         if (loFd == -1)
2699                                 exit_horribly(NULL, "could not open large object %u: %s",
2700                                                           blobOid, PQerrorMessage(conn));
2701
2702                         StartBlob(fout, blobOid);
2703
2704                         /* Now read it in chunks, sending data to archive */
2705                         do
2706                         {
2707                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2708                                 if (cnt < 0)
2709                                         exit_horribly(NULL, "error reading large object %u: %s",
2710                                                                   blobOid, PQerrorMessage(conn));
2711
2712                                 WriteData(fout, buf, cnt);
2713                         } while (cnt > 0);
2714
2715                         lo_close(conn, loFd);
2716
2717                         EndBlob(fout, blobOid);
2718                 }
2719
2720                 PQclear(res);
2721         } while (ntups > 0);
2722
2723         return 1;
2724 }
2725
2726 static void
2727 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2728                                                                                  PQExpBuffer upgrade_buffer,
2729                                                                                  Oid pg_type_oid)
2730 {
2731         PQExpBuffer upgrade_query = createPQExpBuffer();
2732         PGresult   *upgrade_res;
2733         Oid                     pg_type_array_oid;
2734
2735         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2736         appendPQExpBuffer(upgrade_buffer,
2737          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2738                                           pg_type_oid);
2739
2740         /* we only support old >= 8.3 for binary upgrades */
2741         appendPQExpBuffer(upgrade_query,
2742                                           "SELECT typarray "
2743                                           "FROM pg_catalog.pg_type "
2744                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2745                                           pg_type_oid);
2746
2747         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2748
2749         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2750
2751         if (OidIsValid(pg_type_array_oid))
2752         {
2753                 appendPQExpBufferStr(upgrade_buffer,
2754                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2755                 appendPQExpBuffer(upgrade_buffer,
2756                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2757                                                   pg_type_array_oid);
2758         }
2759
2760         PQclear(upgrade_res);
2761         destroyPQExpBuffer(upgrade_query);
2762 }
2763
2764 static bool
2765 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2766                                                                                 PQExpBuffer upgrade_buffer,
2767                                                                                 Oid pg_rel_oid)
2768 {
2769         PQExpBuffer upgrade_query = createPQExpBuffer();
2770         PGresult   *upgrade_res;
2771         Oid                     pg_type_oid;
2772         bool            toast_set = false;
2773
2774         /* we only support old >= 8.3 for binary upgrades */
2775         appendPQExpBuffer(upgrade_query,
2776                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2777                                           "FROM pg_catalog.pg_class c "
2778                                           "LEFT JOIN pg_catalog.pg_class t ON "
2779                                           "  (c.reltoastrelid = t.oid) "
2780                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2781                                           pg_rel_oid);
2782
2783         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2784
2785         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2786
2787         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2788                                                                                          pg_type_oid);
2789
2790         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2791         {
2792                 /* Toast tables do not have pg_type array rows */
2793                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2794                                                                                         PQfnumber(upgrade_res, "trel")));
2795
2796                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2797                 appendPQExpBuffer(upgrade_buffer,
2798                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2799                                                   pg_type_toast_oid);
2800
2801                 toast_set = true;
2802         }
2803
2804         PQclear(upgrade_res);
2805         destroyPQExpBuffer(upgrade_query);
2806
2807         return toast_set;
2808 }
2809
2810 static void
2811 binary_upgrade_set_pg_class_oids(Archive *fout,
2812                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2813                                                                  bool is_index)
2814 {
2815         PQExpBuffer upgrade_query = createPQExpBuffer();
2816         PGresult   *upgrade_res;
2817         Oid                     pg_class_reltoastrelid;
2818         Oid                     pg_index_indexrelid;
2819
2820         appendPQExpBuffer(upgrade_query,
2821                                           "SELECT c.reltoastrelid, i.indexrelid "
2822                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2823                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
2824                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2825                                           pg_class_oid);
2826
2827         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2828
2829         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2830         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
2831
2832         appendPQExpBufferStr(upgrade_buffer,
2833                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
2834
2835         if (!is_index)
2836         {
2837                 appendPQExpBuffer(upgrade_buffer,
2838                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2839                                                   pg_class_oid);
2840                 /* only tables have toast tables, not indexes */
2841                 if (OidIsValid(pg_class_reltoastrelid))
2842                 {
2843                         /*
2844                          * One complexity is that the table definition might not require
2845                          * the creation of a TOAST table, and the TOAST table might have
2846                          * been created long after table creation, when the table was
2847                          * loaded with wide data.  By setting the TOAST oid we force
2848                          * creation of the TOAST heap and TOAST index by the backend so we
2849                          * can cleanly copy the files during binary upgrade.
2850                          */
2851
2852                         appendPQExpBuffer(upgrade_buffer,
2853                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2854                                                           pg_class_reltoastrelid);
2855
2856                         /* every toast table has an index */
2857                         appendPQExpBuffer(upgrade_buffer,
2858                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2859                                                           pg_index_indexrelid);
2860                 }
2861         }
2862         else
2863                 appendPQExpBuffer(upgrade_buffer,
2864                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2865                                                   pg_class_oid);
2866
2867         appendPQExpBufferChar(upgrade_buffer, '\n');
2868
2869         PQclear(upgrade_res);
2870         destroyPQExpBuffer(upgrade_query);
2871 }
2872
2873 /*
2874  * If the DumpableObject is a member of an extension, add a suitable
2875  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2876  */
2877 static void
2878 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2879                                                                 DumpableObject *dobj,
2880                                                                 const char *objlabel)
2881 {
2882         DumpableObject *extobj = NULL;
2883         int                     i;
2884
2885         if (!dobj->ext_member)
2886                 return;
2887
2888         /*
2889          * Find the parent extension.  We could avoid this search if we wanted to
2890          * add a link field to DumpableObject, but the space costs of that would
2891          * be considerable.  We assume that member objects could only have a
2892          * direct dependency on their own extension, not any others.
2893          */
2894         for (i = 0; i < dobj->nDeps; i++)
2895         {
2896                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2897                 if (extobj && extobj->objType == DO_EXTENSION)
2898                         break;
2899                 extobj = NULL;
2900         }
2901         if (extobj == NULL)
2902                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2903
2904         appendPQExpBufferStr(upgrade_buffer,
2905           "\n-- For binary upgrade, handle extension membership the hard way\n");
2906         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2907                                           fmtId(extobj->name),
2908                                           objlabel);
2909 }
2910
2911 /*
2912  * getNamespaces:
2913  *        read all namespaces in the system catalogs and return them in the
2914  * NamespaceInfo* structure
2915  *
2916  *      numNamespaces is set to the number of namespaces read in
2917  */
2918 NamespaceInfo *
2919 getNamespaces(Archive *fout, int *numNamespaces)
2920 {
2921         PGresult   *res;
2922         int                     ntups;
2923         int                     i;
2924         PQExpBuffer query;
2925         NamespaceInfo *nsinfo;
2926         int                     i_tableoid;
2927         int                     i_oid;
2928         int                     i_nspname;
2929         int                     i_rolname;
2930         int                     i_nspacl;
2931
2932         /*
2933          * Before 7.3, there are no real namespaces; create two dummy entries, one
2934          * for user stuff and one for system stuff.
2935          */
2936         if (fout->remoteVersion < 70300)
2937         {
2938                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2939
2940                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2941                 nsinfo[0].dobj.catId.tableoid = 0;
2942                 nsinfo[0].dobj.catId.oid = 0;
2943                 AssignDumpId(&nsinfo[0].dobj);
2944                 nsinfo[0].dobj.name = pg_strdup("public");
2945                 nsinfo[0].rolname = pg_strdup("");
2946                 nsinfo[0].nspacl = pg_strdup("");
2947
2948                 selectDumpableNamespace(&nsinfo[0]);
2949
2950                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2951                 nsinfo[1].dobj.catId.tableoid = 0;
2952                 nsinfo[1].dobj.catId.oid = 1;
2953                 AssignDumpId(&nsinfo[1].dobj);
2954                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2955                 nsinfo[1].rolname = pg_strdup("");
2956                 nsinfo[1].nspacl = pg_strdup("");
2957
2958                 selectDumpableNamespace(&nsinfo[1]);
2959
2960                 *numNamespaces = 2;
2961
2962                 return nsinfo;
2963         }
2964
2965         query = createPQExpBuffer();
2966
2967         /* Make sure we are in proper schema */
2968         selectSourceSchema(fout, "pg_catalog");
2969
2970         /*
2971          * we fetch all namespaces including system ones, so that every object we
2972          * read in can be linked to a containing namespace.
2973          */
2974         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2975                                           "(%s nspowner) AS rolname, "
2976                                           "nspacl FROM pg_namespace",
2977                                           username_subquery);
2978
2979         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2980
2981         ntups = PQntuples(res);
2982
2983         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2984
2985         i_tableoid = PQfnumber(res, "tableoid");
2986         i_oid = PQfnumber(res, "oid");
2987         i_nspname = PQfnumber(res, "nspname");
2988         i_rolname = PQfnumber(res, "rolname");
2989         i_nspacl = PQfnumber(res, "nspacl");
2990
2991         for (i = 0; i < ntups; i++)
2992         {
2993                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2994                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2995                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2996                 AssignDumpId(&nsinfo[i].dobj);
2997                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2998                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2999                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
3000
3001                 /* Decide whether to dump this namespace */
3002                 selectDumpableNamespace(&nsinfo[i]);
3003
3004                 if (strlen(nsinfo[i].rolname) == 0)
3005                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
3006                                           nsinfo[i].dobj.name);
3007         }
3008
3009         PQclear(res);
3010         destroyPQExpBuffer(query);
3011
3012         *numNamespaces = ntups;
3013
3014         return nsinfo;
3015 }
3016
3017 /*
3018  * findNamespace:
3019  *              given a namespace OID and an object OID, look up the info read by
3020  *              getNamespaces
3021  *
3022  * NB: for pre-7.3 source database, we use object OID to guess whether it's
3023  * a system object or not.      In 7.3 and later there is no guessing, and we
3024  * don't use objoid at all.
3025  */
3026 static NamespaceInfo *
3027 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
3028 {
3029         NamespaceInfo *nsinfo;
3030
3031         if (fout->remoteVersion >= 70300)
3032         {
3033                 nsinfo = findNamespaceByOid(nsoid);
3034         }
3035         else
3036         {
3037                 /* This code depends on the dummy objects set up by getNamespaces. */
3038                 Oid                     i;
3039
3040                 if (objoid > g_last_builtin_oid)
3041                         i = 0;                          /* user object */
3042                 else
3043                         i = 1;                          /* system object */
3044                 nsinfo = findNamespaceByOid(i);
3045         }
3046
3047         if (nsinfo == NULL)
3048                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3049
3050         return nsinfo;
3051 }
3052
3053 /*
3054  * getExtensions:
3055  *        read all extensions in the system catalogs and return them in the
3056  * ExtensionInfo* structure
3057  *
3058  *      numExtensions is set to the number of extensions read in
3059  */
3060 ExtensionInfo *
3061 getExtensions(Archive *fout, int *numExtensions)
3062 {
3063         PGresult   *res;
3064         int                     ntups;
3065         int                     i;
3066         PQExpBuffer query;
3067         ExtensionInfo *extinfo;
3068         int                     i_tableoid;
3069         int                     i_oid;
3070         int                     i_extname;
3071         int                     i_nspname;
3072         int                     i_extrelocatable;
3073         int                     i_extversion;
3074         int                     i_extconfig;
3075         int                     i_extcondition;
3076
3077         /*
3078          * Before 9.1, there are no extensions.
3079          */
3080         if (fout->remoteVersion < 90100)
3081         {
3082                 *numExtensions = 0;
3083                 return NULL;
3084         }
3085
3086         query = createPQExpBuffer();
3087
3088         /* Make sure we are in proper schema */
3089         selectSourceSchema(fout, "pg_catalog");
3090
3091         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
3092                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3093                                                  "FROM pg_extension x "
3094                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
3095
3096         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3097
3098         ntups = PQntuples(res);
3099
3100         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3101
3102         i_tableoid = PQfnumber(res, "tableoid");
3103         i_oid = PQfnumber(res, "oid");
3104         i_extname = PQfnumber(res, "extname");
3105         i_nspname = PQfnumber(res, "nspname");
3106         i_extrelocatable = PQfnumber(res, "extrelocatable");
3107         i_extversion = PQfnumber(res, "extversion");
3108         i_extconfig = PQfnumber(res, "extconfig");
3109         i_extcondition = PQfnumber(res, "extcondition");
3110
3111         for (i = 0; i < ntups; i++)
3112         {
3113                 extinfo[i].dobj.objType = DO_EXTENSION;
3114                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3115                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3116                 AssignDumpId(&extinfo[i].dobj);
3117                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3118                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3119                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3120                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3121                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3122                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3123
3124                 /* Decide whether we want to dump it */
3125                 selectDumpableExtension(&(extinfo[i]));
3126         }
3127
3128         PQclear(res);
3129         destroyPQExpBuffer(query);
3130
3131         *numExtensions = ntups;
3132
3133         return extinfo;
3134 }
3135
3136 /*
3137  * getTypes:
3138  *        read all types in the system catalogs and return them in the
3139  * TypeInfo* structure
3140  *
3141  *      numTypes is set to the number of types read in
3142  *
3143  * NB: this must run after getFuncs() because we assume we can do
3144  * findFuncByOid().
3145  */
3146 TypeInfo *
3147 getTypes(Archive *fout, int *numTypes)
3148 {
3149         PGresult   *res;
3150         int                     ntups;
3151         int                     i;
3152         PQExpBuffer query = createPQExpBuffer();
3153         TypeInfo   *tyinfo;
3154         ShellTypeInfo *stinfo;
3155         int                     i_tableoid;
3156         int                     i_oid;
3157         int                     i_typname;
3158         int                     i_typnamespace;
3159         int                     i_typacl;
3160         int                     i_rolname;
3161         int                     i_typinput;
3162         int                     i_typoutput;
3163         int                     i_typelem;
3164         int                     i_typrelid;
3165         int                     i_typrelkind;
3166         int                     i_typtype;
3167         int                     i_typisdefined;
3168         int                     i_isarray;
3169
3170         /*
3171          * we include even the built-in types because those may be used as array
3172          * elements by user-defined types
3173          *
3174          * we filter out the built-in types when we dump out the types
3175          *
3176          * same approach for undefined (shell) types and array types
3177          *
3178          * Note: as of 8.3 we can reliably detect whether a type is an
3179          * auto-generated array type by checking the element type's typarray.
3180          * (Before that the test is capable of generating false positives.) We
3181          * still check for name beginning with '_', though, so as to avoid the
3182          * cost of the subselect probe for all standard types.  This would have to
3183          * be revisited if the backend ever allows renaming of array types.
3184          */
3185
3186         /* Make sure we are in proper schema */
3187         selectSourceSchema(fout, "pg_catalog");
3188
3189         if (fout->remoteVersion >= 90200)
3190         {
3191                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3192                                                   "typnamespace, typacl, "
3193                                                   "(%s typowner) AS rolname, "
3194                                                   "typinput::oid AS typinput, "
3195                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3196                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3197                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3198                                                   "typtype, typisdefined, "
3199                                                   "typname[0] = '_' AND typelem != 0 AND "
3200                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3201                                                   "FROM pg_type",
3202                                                   username_subquery);
3203         }
3204         else if (fout->remoteVersion >= 80300)
3205         {
3206                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3207                                                   "typnamespace, '{=U}' AS typacl, "
3208                                                   "(%s typowner) AS rolname, "
3209                                                   "typinput::oid AS typinput, "
3210                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3211                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3212                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3213                                                   "typtype, typisdefined, "
3214                                                   "typname[0] = '_' AND typelem != 0 AND "
3215                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3216                                                   "FROM pg_type",
3217                                                   username_subquery);
3218         }
3219         else if (fout->remoteVersion >= 70300)
3220         {
3221                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3222                                                   "typnamespace, '{=U}' AS typacl, "
3223                                                   "(%s typowner) AS rolname, "
3224                                                   "typinput::oid AS typinput, "
3225                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3226                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3227                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3228                                                   "typtype, typisdefined, "
3229                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3230                                                   "FROM pg_type",
3231                                                   username_subquery);
3232         }
3233         else if (fout->remoteVersion >= 70100)
3234         {
3235                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3236                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3237                                                   "(%s typowner) AS rolname, "
3238                                                   "typinput::oid AS typinput, "
3239                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3240                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3241                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3242                                                   "typtype, typisdefined, "
3243                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3244                                                   "FROM pg_type",
3245                                                   username_subquery);
3246         }
3247         else
3248         {
3249                 appendPQExpBuffer(query, "SELECT "
3250                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3251                                                   "oid, typname, "
3252                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3253                                                   "(%s typowner) AS rolname, "
3254                                                   "typinput::oid AS typinput, "
3255                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3256                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3257                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3258                                                   "typtype, typisdefined, "
3259                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3260                                                   "FROM pg_type",
3261                                                   username_subquery);
3262         }
3263
3264         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3265
3266         ntups = PQntuples(res);
3267
3268         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3269
3270         i_tableoid = PQfnumber(res, "tableoid");
3271         i_oid = PQfnumber(res, "oid");
3272         i_typname = PQfnumber(res, "typname");
3273         i_typnamespace = PQfnumber(res, "typnamespace");
3274         i_typacl = PQfnumber(res, "typacl");
3275         i_rolname = PQfnumber(res, "rolname");
3276         i_typinput = PQfnumber(res, "typinput");
3277         i_typoutput = PQfnumber(res, "typoutput");
3278         i_typelem = PQfnumber(res, "typelem");
3279         i_typrelid = PQfnumber(res, "typrelid");
3280         i_typrelkind = PQfnumber(res, "typrelkind");
3281         i_typtype = PQfnumber(res, "typtype");
3282         i_typisdefined = PQfnumber(res, "typisdefined");
3283         i_isarray = PQfnumber(res, "isarray");
3284
3285         for (i = 0; i < ntups; i++)
3286         {
3287                 tyinfo[i].dobj.objType = DO_TYPE;
3288                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3289                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3290                 AssignDumpId(&tyinfo[i].dobj);
3291                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3292                 tyinfo[i].dobj.namespace =
3293                         findNamespace(fout,
3294                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3295                                                   tyinfo[i].dobj.catId.oid);
3296                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3297                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3298                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3299                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3300                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3301                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3302                 tyinfo[i].shellType = NULL;
3303
3304                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3305                         tyinfo[i].isDefined = true;
3306                 else
3307                         tyinfo[i].isDefined = false;
3308
3309                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3310                         tyinfo[i].isArray = true;
3311                 else
3312                         tyinfo[i].isArray = false;
3313
3314                 /* Decide whether we want to dump it */
3315                 selectDumpableType(&tyinfo[i]);
3316
3317                 /*
3318                  * If it's a domain, fetch info about its constraints, if any
3319                  */
3320                 tyinfo[i].nDomChecks = 0;
3321                 tyinfo[i].domChecks = NULL;
3322                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3323                         getDomainConstraints(fout, &(tyinfo[i]));
3324
3325                 /*
3326                  * If it's a base type, make a DumpableObject representing a shell
3327                  * definition of the type.      We will need to dump that ahead of the I/O
3328                  * functions for the type.      Similarly, range types need a shell
3329                  * definition in case they have a canonicalize function.
3330                  *
3331                  * Note: the shell type doesn't have a catId.  You might think it
3332                  * should copy the base type's catId, but then it might capture the
3333                  * pg_depend entries for the type, which we don't want.
3334                  */
3335                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3336                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3337                 {
3338                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3339                         stinfo->dobj.objType = DO_SHELL_TYPE;
3340                         stinfo->dobj.catId = nilCatalogId;
3341                         AssignDumpId(&stinfo->dobj);
3342                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3343                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3344                         stinfo->baseType = &(tyinfo[i]);
3345                         tyinfo[i].shellType = stinfo;
3346
3347                         /*
3348                          * Initially mark the shell type as not to be dumped.  We'll only
3349                          * dump it if the I/O or canonicalize functions need to be dumped;
3350                          * this is taken care of while sorting dependencies.
3351                          */
3352                         stinfo->dobj.dump = false;
3353
3354                         /*
3355                          * However, if dumping from pre-7.3, there will be no dependency
3356                          * info so we have to fake it here.  We only need to worry about
3357                          * typinput and typoutput since the other functions only exist
3358                          * post-7.3.
3359                          */
3360                         if (fout->remoteVersion < 70300)
3361                         {
3362                                 Oid                     typinput;
3363                                 Oid                     typoutput;
3364                                 FuncInfo   *funcInfo;
3365
3366                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3367                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3368
3369                                 funcInfo = findFuncByOid(typinput);
3370                                 if (funcInfo && funcInfo->dobj.dump)
3371                                 {
3372                                         /* base type depends on function */
3373                                         addObjectDependency(&tyinfo[i].dobj,
3374                                                                                 funcInfo->dobj.dumpId);
3375                                         /* function depends on shell type */
3376                                         addObjectDependency(&funcInfo->dobj,
3377                                                                                 stinfo->dobj.dumpId);
3378                                         /* mark shell type as to be dumped */
3379                                         stinfo->dobj.dump = true;
3380                                 }
3381
3382                                 funcInfo = findFuncByOid(typoutput);
3383                                 if (funcInfo && funcInfo->dobj.dump)
3384                                 {
3385                                         /* base type depends on function */
3386                                         addObjectDependency(&tyinfo[i].dobj,
3387                                                                                 funcInfo->dobj.dumpId);
3388                                         /* function depends on shell type */
3389                                         addObjectDependency(&funcInfo->dobj,
3390                                                                                 stinfo->dobj.dumpId);
3391                                         /* mark shell type as to be dumped */
3392                                         stinfo->dobj.dump = true;
3393                                 }
3394                         }
3395                 }
3396
3397                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3398                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3399                                           tyinfo[i].dobj.name);
3400         }
3401
3402         *numTypes = ntups;
3403
3404         PQclear(res);
3405
3406         destroyPQExpBuffer(query);
3407
3408         return tyinfo;
3409 }
3410
3411 /*
3412  * getOperators:
3413  *        read all operators in the system catalogs and return them in the
3414  * OprInfo* structure
3415  *
3416  *      numOprs is set to the number of operators read in
3417  */
3418 OprInfo *
3419 getOperators(Archive *fout, int *numOprs)
3420 {
3421         PGresult   *res;
3422         int                     ntups;
3423         int                     i;
3424         PQExpBuffer query = createPQExpBuffer();
3425         OprInfo    *oprinfo;
3426         int                     i_tableoid;
3427         int                     i_oid;
3428         int                     i_oprname;
3429         int                     i_oprnamespace;
3430         int                     i_rolname;
3431         int                     i_oprkind;
3432         int                     i_oprcode;
3433
3434         /*
3435          * find all operators, including builtin operators; we filter out
3436          * system-defined operators at dump-out time.
3437          */
3438
3439         /* Make sure we are in proper schema */
3440         selectSourceSchema(fout, "pg_catalog");
3441
3442         if (fout->remoteVersion >= 70300)
3443         {
3444                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3445                                                   "oprnamespace, "
3446                                                   "(%s oprowner) AS rolname, "
3447                                                   "oprkind, "
3448                                                   "oprcode::oid AS oprcode "
3449                                                   "FROM pg_operator",
3450                                                   username_subquery);
3451         }
3452         else if (fout->remoteVersion >= 70100)
3453         {
3454                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3455                                                   "0::oid AS oprnamespace, "
3456                                                   "(%s oprowner) AS rolname, "
3457                                                   "oprkind, "
3458                                                   "oprcode::oid AS oprcode "
3459                                                   "FROM pg_operator",
3460                                                   username_subquery);
3461         }
3462         else
3463         {
3464                 appendPQExpBuffer(query, "SELECT "
3465                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3466                                                   "oid, oprname, "
3467                                                   "0::oid AS oprnamespace, "
3468                                                   "(%s oprowner) AS rolname, "
3469                                                   "oprkind, "
3470                                                   "oprcode::oid AS oprcode "
3471                                                   "FROM pg_operator",
3472                                                   username_subquery);
3473         }
3474
3475         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3476
3477         ntups = PQntuples(res);
3478         *numOprs = ntups;
3479
3480         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3481
3482         i_tableoid = PQfnumber(res, "tableoid");
3483         i_oid = PQfnumber(res, "oid");
3484         i_oprname = PQfnumber(res, "oprname");
3485         i_oprnamespace = PQfnumber(res, "oprnamespace");
3486         i_rolname = PQfnumber(res, "rolname");
3487         i_oprkind = PQfnumber(res, "oprkind");
3488         i_oprcode = PQfnumber(res, "oprcode");
3489
3490         for (i = 0; i < ntups; i++)
3491         {
3492                 oprinfo[i].dobj.objType = DO_OPERATOR;
3493                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3494                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3495                 AssignDumpId(&oprinfo[i].dobj);
3496                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3497                 oprinfo[i].dobj.namespace =
3498                         findNamespace(fout,
3499                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3500                                                   oprinfo[i].dobj.catId.oid);
3501                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3502                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3503                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3504
3505                 /* Decide whether we want to dump it */
3506                 selectDumpableObject(&(oprinfo[i].dobj));
3507
3508                 if (strlen(oprinfo[i].rolname) == 0)
3509                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3510                                           oprinfo[i].dobj.name);
3511         }
3512
3513         PQclear(res);
3514
3515         destroyPQExpBuffer(query);
3516
3517         return oprinfo;
3518 }
3519
3520 /*
3521  * getCollations:
3522  *        read all collations in the system catalogs and return them in the
3523  * CollInfo* structure
3524  *
3525  *      numCollations is set to the number of collations read in
3526  */
3527 CollInfo *
3528 getCollations(Archive *fout, int *numCollations)
3529 {
3530         PGresult   *res;
3531         int                     ntups;
3532         int                     i;
3533         PQExpBuffer query;
3534         CollInfo   *collinfo;
3535         int                     i_tableoid;
3536         int                     i_oid;
3537         int                     i_collname;
3538         int                     i_collnamespace;
3539         int                     i_rolname;
3540
3541         /* Collations didn't exist pre-9.1 */
3542         if (fout->remoteVersion < 90100)
3543         {
3544                 *numCollations = 0;
3545                 return NULL;
3546         }
3547
3548         query = createPQExpBuffer();
3549
3550         /*
3551          * find all collations, including builtin collations; we filter out
3552          * system-defined collations at dump-out time.
3553          */
3554
3555         /* Make sure we are in proper schema */
3556         selectSourceSchema(fout, "pg_catalog");
3557
3558         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3559                                           "collnamespace, "
3560                                           "(%s collowner) AS rolname "
3561                                           "FROM pg_collation",
3562                                           username_subquery);
3563
3564         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3565
3566         ntups = PQntuples(res);
3567         *numCollations = ntups;
3568
3569         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3570
3571         i_tableoid = PQfnumber(res, "tableoid");
3572         i_oid = PQfnumber(res, "oid");
3573         i_collname = PQfnumber(res, "collname");
3574         i_collnamespace = PQfnumber(res, "collnamespace");
3575         i_rolname = PQfnumber(res, "rolname");
3576
3577         for (i = 0; i < ntups; i++)
3578         {
3579                 collinfo[i].dobj.objType = DO_COLLATION;
3580                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3581                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3582                 AssignDumpId(&collinfo[i].dobj);
3583                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3584                 collinfo[i].dobj.namespace =
3585                         findNamespace(fout,
3586                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3587                                                   collinfo[i].dobj.catId.oid);
3588                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3589
3590                 /* Decide whether we want to dump it */
3591                 selectDumpableObject(&(collinfo[i].dobj));
3592         }
3593
3594         PQclear(res);
3595
3596         destroyPQExpBuffer(query);
3597
3598         return collinfo;
3599 }
3600
3601 /*
3602  * getConversions:
3603  *        read all conversions in the system catalogs and return them in the
3604  * ConvInfo* structure
3605  *
3606  *      numConversions is set to the number of conversions read in
3607  */
3608 ConvInfo *
3609 getConversions(Archive *fout, int *numConversions)
3610 {
3611         PGresult   *res;
3612         int                     ntups;
3613         int                     i;
3614         PQExpBuffer query;
3615         ConvInfo   *convinfo;
3616         int                     i_tableoid;
3617         int                     i_oid;
3618         int                     i_conname;
3619         int                     i_connamespace;
3620         int                     i_rolname;
3621
3622         /* Conversions didn't exist pre-7.3 */
3623         if (fout->remoteVersion < 70300)
3624         {
3625                 *numConversions = 0;
3626                 return NULL;
3627         }
3628
3629         query = createPQExpBuffer();
3630
3631         /*
3632          * find all conversions, including builtin conversions; we filter out
3633          * system-defined conversions at dump-out time.
3634          */
3635
3636         /* Make sure we are in proper schema */
3637         selectSourceSchema(fout, "pg_catalog");
3638
3639         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3640                                           "connamespace, "
3641                                           "(%s conowner) AS rolname "
3642                                           "FROM pg_conversion",
3643                                           username_subquery);
3644
3645         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3646
3647         ntups = PQntuples(res);
3648         *numConversions = ntups;
3649
3650         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3651
3652         i_tableoid = PQfnumber(res, "tableoid");
3653         i_oid = PQfnumber(res, "oid");
3654         i_conname = PQfnumber(res, "conname");
3655         i_connamespace = PQfnumber(res, "connamespace");
3656         i_rolname = PQfnumber(res, "rolname");
3657
3658         for (i = 0; i < ntups; i++)
3659         {
3660                 convinfo[i].dobj.objType = DO_CONVERSION;
3661                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3662                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3663                 AssignDumpId(&convinfo[i].dobj);
3664                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3665                 convinfo[i].dobj.namespace =
3666                         findNamespace(fout,
3667                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3668                                                   convinfo[i].dobj.catId.oid);
3669                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3670
3671                 /* Decide whether we want to dump it */
3672                 selectDumpableObject(&(convinfo[i].dobj));
3673         }
3674
3675         PQclear(res);
3676
3677         destroyPQExpBuffer(query);
3678
3679         return convinfo;
3680 }
3681
3682 /*
3683  * getOpclasses:
3684  *        read all opclasses in the system catalogs and return them in the
3685  * OpclassInfo* structure
3686  *
3687  *      numOpclasses is set to the number of opclasses read in
3688  */
3689 OpclassInfo *
3690 getOpclasses(Archive *fout, int *numOpclasses)
3691 {
3692         PGresult   *res;
3693         int                     ntups;
3694         int                     i;
3695         PQExpBuffer query = createPQExpBuffer();
3696         OpclassInfo *opcinfo;
3697         int                     i_tableoid;
3698         int                     i_oid;
3699         int                     i_opcname;
3700         int                     i_opcnamespace;
3701         int                     i_rolname;
3702
3703         /*
3704          * find all opclasses, including builtin opclasses; we filter out
3705          * system-defined opclasses at dump-out time.
3706          */
3707
3708         /* Make sure we are in proper schema */
3709         selectSourceSchema(fout, "pg_catalog");
3710
3711         if (fout->remoteVersion >= 70300)
3712         {
3713                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3714                                                   "opcnamespace, "
3715                                                   "(%s opcowner) AS rolname "
3716                                                   "FROM pg_opclass",
3717                                                   username_subquery);
3718         }
3719         else if (fout->remoteVersion >= 70100)
3720         {
3721                 appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
3722                                                          "0::oid AS opcnamespace, "
3723                                                          "''::name AS rolname "
3724                                                          "FROM pg_opclass");
3725         }
3726         else
3727         {
3728                 appendPQExpBufferStr(query, "SELECT "
3729                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3730                                                          "oid, opcname, "
3731                                                          "0::oid AS opcnamespace, "
3732                                                          "''::name AS rolname "
3733                                                          "FROM pg_opclass");
3734         }
3735
3736         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3737
3738         ntups = PQntuples(res);
3739         *numOpclasses = ntups;
3740
3741         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3742
3743         i_tableoid = PQfnumber(res, "tableoid");
3744         i_oid = PQfnumber(res, "oid");
3745         i_opcname = PQfnumber(res, "opcname");
3746         i_opcnamespace = PQfnumber(res, "opcnamespace");
3747         i_rolname = PQfnumber(res, "rolname");
3748
3749         for (i = 0; i < ntups; i++)
3750         {
3751                 opcinfo[i].dobj.objType = DO_OPCLASS;
3752                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3753                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3754                 AssignDumpId(&opcinfo[i].dobj);
3755                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3756                 opcinfo[i].dobj.namespace =
3757                         findNamespace(fout,
3758                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3759                                                   opcinfo[i].dobj.catId.oid);
3760                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3761
3762                 /* Decide whether we want to dump it */
3763                 selectDumpableObject(&(opcinfo[i].dobj));
3764
3765                 if (fout->remoteVersion >= 70300)
3766                 {
3767                         if (strlen(opcinfo[i].rolname) == 0)
3768                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3769                                                   opcinfo[i].dobj.name);
3770                 }
3771         }
3772
3773         PQclear(res);
3774
3775         destroyPQExpBuffer(query);
3776
3777         return opcinfo;
3778 }
3779
3780 /*
3781  * getOpfamilies:
3782  *        read all opfamilies in the system catalogs and return them in the
3783  * OpfamilyInfo* structure
3784  *
3785  *      numOpfamilies is set to the number of opfamilies read in
3786  */
3787 OpfamilyInfo *
3788 getOpfamilies(Archive *fout, int *numOpfamilies)
3789 {
3790         PGresult   *res;
3791         int                     ntups;
3792         int                     i;
3793         PQExpBuffer query;
3794         OpfamilyInfo *opfinfo;
3795         int                     i_tableoid;
3796         int                     i_oid;
3797         int                     i_opfname;
3798         int                     i_opfnamespace;
3799         int                     i_rolname;
3800
3801         /* Before 8.3, there is no separate concept of opfamilies */
3802         if (fout->remoteVersion < 80300)
3803         {
3804                 *numOpfamilies = 0;
3805                 return NULL;
3806         }
3807
3808         query = createPQExpBuffer();
3809
3810         /*
3811          * find all opfamilies, including builtin opfamilies; we filter out
3812          * system-defined opfamilies at dump-out time.
3813          */
3814
3815         /* Make sure we are in proper schema */
3816         selectSourceSchema(fout, "pg_catalog");
3817
3818         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3819                                           "opfnamespace, "
3820                                           "(%s opfowner) AS rolname "
3821                                           "FROM pg_opfamily",
3822                                           username_subquery);
3823
3824         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3825
3826         ntups = PQntuples(res);
3827         *numOpfamilies = ntups;
3828
3829         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3830
3831         i_tableoid = PQfnumber(res, "tableoid");
3832         i_oid = PQfnumber(res, "oid");
3833         i_opfname = PQfnumber(res, "opfname");
3834         i_opfnamespace = PQfnumber(res, "opfnamespace");
3835         i_rolname = PQfnumber(res, "rolname");
3836
3837         for (i = 0; i < ntups; i++)
3838         {
3839                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3840                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3841                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3842                 AssignDumpId(&opfinfo[i].dobj);
3843                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3844                 opfinfo[i].dobj.namespace =
3845                         findNamespace(fout,
3846                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3847                                                   opfinfo[i].dobj.catId.oid);
3848                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3849
3850                 /* Decide whether we want to dump it */
3851                 selectDumpableObject(&(opfinfo[i].dobj));
3852
3853                 if (fout->remoteVersion >= 70300)
3854                 {
3855                         if (strlen(opfinfo[i].rolname) == 0)
3856                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3857                                                   opfinfo[i].dobj.name);
3858                 }
3859         }
3860
3861         PQclear(res);
3862
3863         destroyPQExpBuffer(query);
3864
3865         return opfinfo;
3866 }
3867
3868 /*
3869  * getAggregates:
3870  *        read all the user-defined aggregates in the system catalogs and
3871  * return them in the AggInfo* structure
3872  *
3873  * numAggs is set to the number of aggregates read in
3874  */
3875 AggInfo *
3876 getAggregates(Archive *fout, int *numAggs)
3877 {
3878         PGresult   *res;
3879         int                     ntups;
3880         int                     i;
3881         PQExpBuffer query = createPQExpBuffer();
3882         AggInfo    *agginfo;
3883         int                     i_tableoid;
3884         int                     i_oid;
3885         int                     i_aggname;
3886         int                     i_aggnamespace;
3887         int                     i_pronargs;
3888         int                     i_proargtypes;
3889         int                     i_rolname;
3890         int                     i_aggacl;
3891         int                     i_proiargs;
3892
3893         /* Make sure we are in proper schema */
3894         selectSourceSchema(fout, "pg_catalog");
3895
3896         /*
3897          * Find all user-defined aggregates.  See comment in getFuncs() for the
3898          * rationale behind the filtering logic.
3899          */
3900
3901         if (fout->remoteVersion >= 80400)
3902         {
3903                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3904                                                   "pronamespace AS aggnamespace, "
3905                                                   "pronargs, proargtypes, "
3906                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
3907                                                   "(%s proowner) AS rolname, "
3908                                                   "proacl AS aggacl "
3909                                                   "FROM pg_proc p "
3910                                                   "WHERE proisagg AND ("
3911                                                   "pronamespace != "
3912                                                   "(SELECT oid FROM pg_namespace "
3913                                                   "WHERE nspname = 'pg_catalog')",
3914                                                   username_subquery);
3915                 if (binary_upgrade && fout->remoteVersion >= 90100)
3916                         appendPQExpBufferStr(query,
3917                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3918                                                                  "classid = 'pg_proc'::regclass AND "
3919                                                                  "objid = p.oid AND "
3920                                                                  "refclassid = 'pg_extension'::regclass AND "
3921                                                                  "deptype = 'e')");
3922                 appendPQExpBufferChar(query, ')');
3923         }
3924         else if (fout->remoteVersion >= 80200)
3925         {
3926                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3927                                                   "pronamespace AS aggnamespace, "
3928                                                   "pronargs, proargtypes, "
3929                                                   "NULL::text AS proiargs,"
3930                                                   "(%s proowner) AS rolname, "
3931                                                   "proacl AS aggacl "
3932                                                   "FROM pg_proc p "
3933                                                   "WHERE proisagg AND ("
3934                                                   "pronamespace != "
3935                                                   "(SELECT oid FROM pg_namespace "
3936                                                   "WHERE nspname = 'pg_catalog'))",
3937                                                   username_subquery);
3938         }
3939         else if (fout->remoteVersion >= 70300)
3940         {
3941                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3942                                                   "pronamespace AS aggnamespace, "
3943                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3944                                                   "proargtypes, "
3945                                                   "NULL::text AS proiargs, "
3946                                                   "(%s proowner) AS rolname, "
3947                                                   "proacl AS aggacl "
3948                                                   "FROM pg_proc "
3949                                                   "WHERE proisagg "
3950                                                   "AND pronamespace != "
3951                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3952                                                   username_subquery);
3953         }
3954         else if (fout->remoteVersion >= 70100)
3955         {
3956                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3957                                                   "0::oid AS aggnamespace, "
3958                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3959                                                   "aggbasetype AS proargtypes, "
3960                                                   "NULL::text AS proiargs, "
3961                                                   "(%s aggowner) AS rolname, "
3962                                                   "'{=X}' AS aggacl "
3963                                                   "FROM pg_aggregate "
3964                                                   "where oid > '%u'::oid",
3965                                                   username_subquery,
3966                                                   g_last_builtin_oid);
3967         }
3968         else
3969         {
3970                 appendPQExpBuffer(query, "SELECT "
3971                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3972                                                   "oid, aggname, "
3973                                                   "0::oid AS aggnamespace, "
3974                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3975                                                   "aggbasetype AS proargtypes, "
3976                                                   "NULL::text AS proiargs, "
3977                                                   "(%s aggowner) AS rolname, "
3978                                                   "'{=X}' AS aggacl "
3979                                                   "FROM pg_aggregate "
3980                                                   "where oid > '%u'::oid",
3981                                                   username_subquery,
3982                                                   g_last_builtin_oid);
3983         }
3984
3985         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3986
3987         ntups = PQntuples(res);
3988         *numAggs = ntups;
3989
3990         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3991
3992         i_tableoid = PQfnumber(res, "tableoid");
3993         i_oid = PQfnumber(res, "oid");
3994         i_aggname = PQfnumber(res, "aggname");
3995         i_aggnamespace = PQfnumber(res, "aggnamespace");
3996         i_pronargs = PQfnumber(res, "pronargs");
3997         i_proargtypes = PQfnumber(res, "proargtypes");
3998         i_rolname = PQfnumber(res, "rolname");
3999         i_aggacl = PQfnumber(res, "aggacl");
4000         i_proiargs = PQfnumber(res, "proiargs");
4001
4002         for (i = 0; i < ntups; i++)
4003         {
4004                 agginfo[i].aggfn.dobj.objType = DO_AGG;
4005                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4006                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4007                 AssignDumpId(&agginfo[i].aggfn.dobj);
4008                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
4009                 agginfo[i].aggfn.dobj.namespace =
4010                         findNamespace(fout,
4011                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
4012                                                   agginfo[i].aggfn.dobj.catId.oid);
4013                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4014                 if (strlen(agginfo[i].aggfn.rolname) == 0)
4015                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
4016                                           agginfo[i].aggfn.dobj.name);
4017                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
4018                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
4019                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
4020                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4021                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
4022                 if (agginfo[i].aggfn.nargs == 0)
4023                         agginfo[i].aggfn.argtypes = NULL;
4024                 else
4025                 {
4026                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
4027                         if (fout->remoteVersion >= 70300)
4028                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
4029                                                           agginfo[i].aggfn.argtypes,
4030                                                           agginfo[i].aggfn.nargs);
4031                         else
4032                                 /* it's just aggbasetype */
4033                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
4034                 }
4035
4036                 /* Decide whether we want to dump it */
4037                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
4038         }
4039
4040         PQclear(res);
4041
4042         destroyPQExpBuffer(query);
4043
4044         return agginfo;
4045 }
4046
4047 /*
4048  * getFuncs:
4049  *        read all the user-defined functions in the system catalogs and
4050  * return them in the FuncInfo* structure
4051  *
4052  * numFuncs is set to the number of functions read in
4053  */
4054 FuncInfo *
4055 getFuncs(Archive *fout, int *numFuncs)
4056 {
4057         PGresult   *res;
4058         int                     ntups;
4059         int                     i;
4060         PQExpBuffer query = createPQExpBuffer();
4061         FuncInfo   *finfo;
4062         int                     i_tableoid;
4063         int                     i_oid;
4064         int                     i_proname;
4065         int                     i_pronamespace;
4066         int                     i_rolname;
4067         int                     i_prolang;
4068         int                     i_pronargs;
4069         int                     i_proargtypes;
4070         int                     i_prorettype;
4071         int                     i_proacl;
4072         int                     i_proiargs;
4073
4074         /* Make sure we are in proper schema */
4075         selectSourceSchema(fout, "pg_catalog");
4076
4077         /*
4078          * Find all user-defined functions.  Normally we can exclude functions in
4079          * pg_catalog, which is worth doing since there are several thousand of
4080          * 'em.  However, there are some extensions that create functions in
4081          * pg_catalog.  In normal dumps we can still ignore those --- but in
4082          * binary-upgrade mode, we must dump the member objects of the extension,
4083          * so be sure to fetch any such functions.
4084          *
4085          * Also, in 9.2 and up, exclude functions that are internally dependent on
4086          * something else, since presumably those will be created as a result of
4087          * creating the something else.  This currently only acts to suppress
4088          * constructor functions for range types.  Note that this is OK only
4089          * because the constructors don't have any dependencies the range type
4090          * doesn't have; otherwise we might not get creation ordering correct.
4091          */
4092
4093         if (fout->remoteVersion >= 80400)
4094         {
4095                 appendPQExpBuffer(query,
4096                                                   "SELECT tableoid, oid, proname, prolang, "
4097                                                   "pronargs, proargtypes, prorettype, proacl, "
4098                                                   "pronamespace, "
4099                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4100                                                   "(%s proowner) AS rolname "
4101                                                   "FROM pg_proc p "
4102                                                   "WHERE NOT proisagg AND ("
4103                                                   "pronamespace != "
4104                                                   "(SELECT oid FROM pg_namespace "
4105                                                   "WHERE nspname = 'pg_catalog')",
4106                                                   username_subquery);
4107                 if (fout->remoteVersion >= 90200)
4108                         appendPQExpBufferStr(query,
4109                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4110                                                                  "WHERE classid = 'pg_proc'::regclass AND "
4111                                                                  "objid = p.oid AND deptype = 'i')");
4112                 if (binary_upgrade && fout->remoteVersion >= 90100)
4113                         appendPQExpBufferStr(query,
4114                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4115                                                                  "classid = 'pg_proc'::regclass AND "
4116                                                                  "objid = p.oid AND "
4117                                                                  "refclassid = 'pg_extension'::regclass AND "
4118                                                                  "deptype = 'e')");
4119                 appendPQExpBufferChar(query, ')');
4120         }
4121         else if (fout->remoteVersion >= 70300)
4122         {
4123                 appendPQExpBuffer(query,
4124                                                   "SELECT tableoid, oid, proname, prolang, "
4125                                                   "pronargs, proargtypes, prorettype, proacl, "
4126                                                   "pronamespace, "
4127                                                   "NULL::text AS proiargs,"
4128                                                   "(%s proowner) AS rolname "
4129                                                   "FROM pg_proc p "
4130                                                   "WHERE NOT proisagg AND ("
4131                                                   "pronamespace != "
4132                                                   "(SELECT oid FROM pg_namespace "
4133                                                   "WHERE nspname = 'pg_catalog'))",
4134                                                   username_subquery);
4135         }
4136         else if (fout->remoteVersion >= 70100)
4137         {
4138                 appendPQExpBuffer(query,
4139                                                   "SELECT tableoid, oid, proname, prolang, "
4140                                                   "pronargs, proargtypes, prorettype, "
4141                                                   "'{=X}' AS proacl, "
4142                                                   "0::oid AS pronamespace, "
4143                                                   "NULL::text AS proiargs,"
4144                                                   "(%s proowner) AS rolname "
4145                                                   "FROM pg_proc "
4146                                                   "WHERE pg_proc.oid > '%u'::oid",
4147                                                   username_subquery,
4148                                                   g_last_builtin_oid);
4149         }
4150         else
4151         {
4152                 appendPQExpBuffer(query,
4153                                                   "SELECT "
4154                                                   "(SELECT oid FROM pg_class "
4155                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4156                                                   "oid, proname, prolang, "
4157                                                   "pronargs, proargtypes, prorettype, "
4158                                                   "'{=X}' AS proacl, "
4159                                                   "0::oid AS pronamespace, "
4160                                                   "NULL::text AS proiargs,"
4161                                                   "(%s proowner) AS rolname "
4162                                                   "FROM pg_proc "
4163                                                   "where pg_proc.oid > '%u'::oid",
4164                                                   username_subquery,
4165                                                   g_last_builtin_oid);
4166         }
4167
4168         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4169
4170         ntups = PQntuples(res);
4171
4172         *numFuncs = ntups;
4173
4174         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4175
4176         i_tableoid = PQfnumber(res, "tableoid");
4177         i_oid = PQfnumber(res, "oid");
4178         i_proname = PQfnumber(res, "proname");
4179         i_pronamespace = PQfnumber(res, "pronamespace");
4180         i_rolname = PQfnumber(res, "rolname");
4181         i_prolang = PQfnumber(res, "prolang");
4182         i_pronargs = PQfnumber(res, "pronargs");
4183         i_proargtypes = PQfnumber(res, "proargtypes");
4184         i_prorettype = PQfnumber(res, "prorettype");
4185         i_proacl = PQfnumber(res, "proacl");
4186         i_proiargs = PQfnumber(res, "proiargs");
4187
4188         for (i = 0; i < ntups; i++)
4189         {
4190                 finfo[i].dobj.objType = DO_FUNC;
4191                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4192                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4193                 AssignDumpId(&finfo[i].dobj);
4194                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4195                 finfo[i].dobj.namespace =
4196                         findNamespace(fout,
4197                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4198                                                   finfo[i].dobj.catId.oid);
4199                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4200                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4201                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4202                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4203                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4204                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4205                 if (finfo[i].nargs == 0)
4206                         finfo[i].argtypes = NULL;
4207                 else
4208                 {
4209                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4210                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4211                                                   finfo[i].argtypes, finfo[i].nargs);
4212                 }
4213
4214                 /* Decide whether we want to dump it */
4215                 selectDumpableObject(&(finfo[i].dobj));
4216
4217                 if (strlen(finfo[i].rolname) == 0)
4218                         write_msg(NULL,
4219                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4220                                           finfo[i].dobj.name);
4221         }
4222
4223         PQclear(res);
4224
4225         destroyPQExpBuffer(query);
4226
4227         return finfo;
4228 }
4229
4230 /*
4231  * getTables
4232  *        read all the user-defined tables (no indexes, no catalogs)
4233  * in the system catalogs return them in the TableInfo* structure
4234  *
4235  * numTables is set to the number of tables read in
4236  */
4237 TableInfo *
4238 getTables(Archive *fout, int *numTables)
4239 {
4240         PGresult   *res;
4241         int                     ntups;
4242         int                     i;
4243         PQExpBuffer query = createPQExpBuffer();
4244         TableInfo  *tblinfo;
4245         int                     i_reltableoid;
4246         int                     i_reloid;
4247         int                     i_relname;
4248         int                     i_relnamespace;
4249         int                     i_relkind;
4250         int                     i_relacl;
4251         int                     i_rolname;
4252         int                     i_relchecks;
4253         int                     i_relhastriggers;
4254         int                     i_relhasindex;
4255         int                     i_relhasrules;
4256         int                     i_relhasoids;
4257         int                     i_relfrozenxid;
4258         int                     i_toastoid;
4259         int                     i_toastfrozenxid;
4260         int                     i_relpersistence;
4261         int                     i_relispopulated;
4262         int                     i_relreplident;
4263         int                     i_owning_tab;
4264         int                     i_owning_col;
4265         int                     i_reltablespace;
4266         int                     i_reloptions;
4267         int                     i_checkoption;
4268         int                     i_toastreloptions;
4269         int                     i_reloftype;
4270         int                     i_relpages;
4271
4272         /* Make sure we are in proper schema */
4273         selectSourceSchema(fout, "pg_catalog");
4274
4275         /*
4276          * Find all the tables and table-like objects.
4277          *
4278          * We include system catalogs, so that we can work if a user table is
4279          * defined to inherit from a system catalog (pretty weird, but...)
4280          *
4281          * We ignore relations that are not ordinary tables, sequences, views,
4282          * materialized views, composite types, or foreign tables.
4283          *
4284          * Composite-type table entries won't be dumped as such, but we have to
4285          * make a DumpableObject for them so that we can track dependencies of the
4286          * composite type (pg_depend entries for columns of the composite type
4287          * link to the pg_class entry not the pg_type entry).
4288          *
4289          * Note: in this phase we should collect only a minimal amount of
4290          * information about each table, basically just enough to decide if it is
4291          * interesting. We must fetch all tables in this phase because otherwise
4292          * we cannot correctly identify inherited columns, owned sequences, etc.
4293          */
4294
4295         if (fout->remoteVersion >= 90400)
4296         {
4297                 /*
4298                  * Left join to pick up dependency info linking sequences to their
4299                  * owning column, if any (note this dependency is AUTO as of 8.2)
4300                  */
4301                 appendPQExpBuffer(query,
4302                                                   "SELECT c.tableoid, c.oid, c.relname, "
4303                                                   "c.relacl, c.relkind, c.relnamespace, "
4304                                                   "(%s c.relowner) AS rolname, "
4305                                                   "c.relchecks, c.relhastriggers, "
4306                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4307                                                   "c.relfrozenxid, tc.oid AS toid, "
4308                                                   "tc.relfrozenxid AS tfrozenxid, "
4309                                                   "c.relpersistence, c.relispopulated, "
4310                                                   "c.relreplident, c.relpages, "
4311                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4312                                                   "d.refobjid AS owning_tab, "
4313                                                   "d.refobjsubid AS owning_col, "
4314                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4315                                                 "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4316                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4317                                                            "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4318                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4319                                                   "FROM pg_class c "
4320                                                   "LEFT JOIN pg_depend d ON "
4321                                                   "(c.relkind = '%c' AND "
4322                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4323                                                   "d.objsubid = 0 AND "
4324                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4325                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4326                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4327                                                   "ORDER BY c.oid",
4328                                                   username_subquery,
4329                                                   RELKIND_SEQUENCE,
4330                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4331                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4332                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4333         }
4334         else if (fout->remoteVersion >= 90300)
4335         {
4336                 /*
4337                  * Left join to pick up dependency info linking sequences to their
4338                  * owning column, if any (note this dependency is AUTO as of 8.2)
4339                  */
4340                 appendPQExpBuffer(query,
4341                                                   "SELECT c.tableoid, c.oid, c.relname, "
4342                                                   "c.relacl, c.relkind, c.relnamespace, "
4343                                                   "(%s c.relowner) AS rolname, "
4344                                                   "c.relchecks, c.relhastriggers, "
4345                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4346                                                   "c.relfrozenxid, tc.oid AS toid, "
4347                                                   "tc.relfrozenxid AS tfrozenxid, "
4348                                                   "c.relpersistence, c.relispopulated, "
4349                                                   "'d' AS relreplident, c.relpages, "
4350                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4351                                                   "d.refobjid AS owning_tab, "
4352                                                   "d.refobjsubid AS owning_col, "
4353                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4354                                                 "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4355                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4356                                                            "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4357                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4358                                                   "FROM pg_class c "
4359                                                   "LEFT JOIN pg_depend d ON "
4360                                                   "(c.relkind = '%c' AND "
4361                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4362                                                   "d.objsubid = 0 AND "
4363                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4364                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4365                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4366                                                   "ORDER BY c.oid",
4367                                                   username_subquery,
4368                                                   RELKIND_SEQUENCE,
4369                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4370                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4371                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4372         }
4373         else if (fout->remoteVersion >= 90100)
4374         {
4375                 /*
4376                  * Left join to pick up dependency info linking sequences to their
4377                  * owning column, if any (note this dependency is AUTO as of 8.2)
4378                  */
4379                 appendPQExpBuffer(query,
4380                                                   "SELECT c.tableoid, c.oid, c.relname, "
4381                                                   "c.relacl, c.relkind, c.relnamespace, "
4382                                                   "(%s c.relowner) AS rolname, "
4383                                                   "c.relchecks, c.relhastriggers, "
4384                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4385                                                   "c.relfrozenxid, tc.oid AS toid, "
4386                                                   "tc.relfrozenxid AS tfrozenxid, "
4387                                                   "c.relpersistence, 't' as relispopulated, "
4388                                                   "'d' AS relreplident, c.relpages, "
4389                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4390                                                   "d.refobjid AS owning_tab, "
4391                                                   "d.refobjsubid AS owning_col, "
4392                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4393                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4394                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4395                                                   "FROM pg_class c "
4396                                                   "LEFT JOIN pg_depend d ON "
4397                                                   "(c.relkind = '%c' AND "
4398                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4399                                                   "d.objsubid = 0 AND "
4400                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4401                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4402                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4403                                                   "ORDER BY c.oid",
4404                                                   username_subquery,
4405                                                   RELKIND_SEQUENCE,
4406                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4407                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4408                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4409         }
4410         else if (fout->remoteVersion >= 90000)
4411         {
4412                 /*
4413                  * Left join to pick up dependency info linking sequences to their
4414                  * owning column, if any (note this dependency is AUTO as of 8.2)
4415                  */
4416                 appendPQExpBuffer(query,
4417                                                   "SELECT c.tableoid, c.oid, c.relname, "
4418                                                   "c.relacl, c.relkind, c.relnamespace, "
4419                                                   "(%s c.relowner) AS rolname, "
4420                                                   "c.relchecks, c.relhastriggers, "
4421                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4422                                                   "c.relfrozenxid, tc.oid AS toid, "
4423                                                   "tc.relfrozenxid AS tfrozenxid, "
4424                                                   "'p' AS relpersistence, 't' as relispopulated, "
4425                                                   "'d' AS relreplident, c.relpages, "
4426                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4427                                                   "d.refobjid AS owning_tab, "
4428                                                   "d.refobjsubid AS owning_col, "
4429                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4430                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4431                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4432                                                   "FROM pg_class c "
4433                                                   "LEFT JOIN pg_depend d ON "
4434                                                   "(c.relkind = '%c' AND "
4435                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4436                                                   "d.objsubid = 0 AND "
4437                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4438                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4439                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4440                                                   "ORDER BY c.oid",
4441                                                   username_subquery,
4442                                                   RELKIND_SEQUENCE,
4443                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4444                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4445         }
4446         else if (fout->remoteVersion >= 80400)
4447         {
4448                 /*
4449                  * Left join to pick up dependency info linking sequences to their
4450                  * owning column, if any (note this dependency is AUTO as of 8.2)
4451                  */
4452                 appendPQExpBuffer(query,
4453                                                   "SELECT c.tableoid, c.oid, c.relname, "
4454                                                   "c.relacl, c.relkind, c.relnamespace, "
4455                                                   "(%s c.relowner) AS rolname, "
4456                                                   "c.relchecks, c.relhastriggers, "
4457                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4458                                                   "c.relfrozenxid, tc.oid AS toid, "
4459                                                   "tc.relfrozenxid AS tfrozenxid, "
4460                                                   "'p' AS relpersistence, 't' as relispopulated, "
4461                                                   "'d' AS relreplident, c.relpages, "
4462                                                   "NULL AS reloftype, "
4463                                                   "d.refobjid AS owning_tab, "
4464                                                   "d.refobjsubid AS owning_col, "
4465                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4466                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4467                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4468                                                   "FROM pg_class c "
4469                                                   "LEFT JOIN pg_depend d ON "
4470                                                   "(c.relkind = '%c' AND "
4471                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4472                                                   "d.objsubid = 0 AND "
4473                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4474                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4475                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4476                                                   "ORDER BY c.oid",
4477                                                   username_subquery,
4478                                                   RELKIND_SEQUENCE,
4479                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4480                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4481         }
4482         else if (fout->remoteVersion >= 80200)
4483         {
4484                 /*
4485                  * Left join to pick up dependency info linking sequences to their
4486                  * owning column, if any (note this dependency is AUTO as of 8.2)
4487                  */
4488                 appendPQExpBuffer(query,
4489                                                   "SELECT c.tableoid, c.oid, c.relname, "
4490                                                   "c.relacl, c.relkind, c.relnamespace, "
4491                                                   "(%s c.relowner) AS rolname, "
4492                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4493                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4494                                                   "c.relfrozenxid, tc.oid AS toid, "
4495                                                   "tc.relfrozenxid AS tfrozenxid, "
4496                                                   "'p' AS relpersistence, 't' as relispopulated, "
4497                                                   "'d' AS relreplident, c.relpages, "
4498                                                   "NULL AS reloftype, "
4499                                                   "d.refobjid AS owning_tab, "
4500                                                   "d.refobjsubid AS owning_col, "
4501                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4502                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4503                                                   "NULL AS toast_reloptions "
4504                                                   "FROM pg_class c "
4505                                                   "LEFT JOIN pg_depend d ON "
4506                                                   "(c.relkind = '%c' AND "
4507                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4508                                                   "d.objsubid = 0 AND "
4509                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4510                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4511                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4512                                                   "ORDER BY c.oid",
4513                                                   username_subquery,
4514                                                   RELKIND_SEQUENCE,
4515                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4516                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4517         }
4518         else if (fout->remoteVersion >= 80000)
4519         {
4520                 /*
4521                  * Left join to pick up dependency info linking sequences to their
4522                  * owning column, if any
4523                  */
4524                 appendPQExpBuffer(query,
4525                                                   "SELECT c.tableoid, c.oid, relname, "
4526                                                   "relacl, relkind, relnamespace, "
4527                                                   "(%s relowner) AS rolname, "
4528                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4529                                                   "relhasindex, relhasrules, relhasoids, "
4530                                                   "0 AS relfrozenxid, "
4531                                                   "0 AS toid, "
4532                                                   "0 AS tfrozenxid, "
4533                                                   "'p' AS relpersistence, 't' as relispopulated, "
4534                                                   "'d' AS relreplident, relpages, "
4535                                                   "NULL AS reloftype, "
4536                                                   "d.refobjid AS owning_tab, "
4537                                                   "d.refobjsubid AS owning_col, "
4538                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4539                                                   "NULL AS reloptions, "
4540                                                   "NULL AS toast_reloptions "
4541                                                   "FROM pg_class c "
4542                                                   "LEFT JOIN pg_depend d ON "
4543                                                   "(c.relkind = '%c' AND "
4544                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4545                                                   "d.objsubid = 0 AND "
4546                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4547                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4548                                                   "ORDER BY c.oid",
4549                                                   username_subquery,
4550                                                   RELKIND_SEQUENCE,
4551                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4552                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4553         }
4554         else if (fout->remoteVersion >= 70300)
4555         {
4556                 /*
4557                  * Left join to pick up dependency info linking sequences to their
4558                  * owning column, if any
4559                  */
4560                 appendPQExpBuffer(query,
4561                                                   "SELECT c.tableoid, c.oid, relname, "
4562                                                   "relacl, relkind, relnamespace, "
4563                                                   "(%s relowner) AS rolname, "
4564                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4565                                                   "relhasindex, relhasrules, relhasoids, "
4566                                                   "0 AS relfrozenxid, "
4567                                                   "0 AS toid, "
4568                                                   "0 AS tfrozenxid, "
4569                                                   "'p' AS relpersistence, 't' as relispopulated, "
4570                                                   "'d' AS relreplident, relpages, "
4571                                                   "NULL AS reloftype, "
4572                                                   "d.refobjid AS owning_tab, "
4573                                                   "d.refobjsubid AS owning_col, "
4574                                                   "NULL AS reltablespace, "
4575                                                   "NULL AS reloptions, "
4576                                                   "NULL AS toast_reloptions "
4577                                                   "FROM pg_class c "
4578                                                   "LEFT JOIN pg_depend d ON "
4579                                                   "(c.relkind = '%c' AND "
4580                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4581                                                   "d.objsubid = 0 AND "
4582                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4583                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4584                                                   "ORDER BY c.oid",
4585                                                   username_subquery,
4586                                                   RELKIND_SEQUENCE,
4587                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4588                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4589         }
4590         else if (fout->remoteVersion >= 70200)
4591         {
4592                 appendPQExpBuffer(query,
4593                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4594                                                   "0::oid AS relnamespace, "
4595                                                   "(%s relowner) AS rolname, "
4596                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4597                                                   "relhasindex, relhasrules, relhasoids, "
4598                                                   "0 AS relfrozenxid, "
4599                                                   "0 AS toid, "
4600                                                   "0 AS tfrozenxid, "
4601                                                   "'p' AS relpersistence, 't' as relispopulated, "
4602                                                   "'d' AS relreplident, relpages, "
4603                                                   "NULL AS reloftype, "
4604                                                   "NULL::oid AS owning_tab, "
4605                                                   "NULL::int4 AS owning_col, "
4606                                                   "NULL AS reltablespace, "
4607                                                   "NULL AS reloptions, "
4608                                                   "NULL AS toast_reloptions "
4609                                                   "FROM pg_class "
4610                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4611                                                   "ORDER BY oid",
4612                                                   username_subquery,
4613                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4614         }
4615         else if (fout->remoteVersion >= 70100)
4616         {
4617                 /* all tables have oids in 7.1 */
4618                 appendPQExpBuffer(query,
4619                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4620                                                   "0::oid AS relnamespace, "
4621                                                   "(%s relowner) AS rolname, "
4622                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4623                                                   "relhasindex, relhasrules, "
4624                                                   "'t'::bool AS relhasoids, "
4625                                                   "0 AS relfrozenxid, "
4626                                                   "0 AS toid, "
4627                                                   "0 AS tfrozenxid, "
4628                                                   "'p' AS relpersistence, 't' as relispopulated, "
4629                                                   "'d' AS relreplident, relpages, "
4630                                                   "NULL AS reloftype, "
4631                                                   "NULL::oid AS owning_tab, "
4632                                                   "NULL::int4 AS owning_col, "
4633                                                   "NULL AS reltablespace, "
4634                                                   "NULL AS reloptions, "
4635                                                   "NULL AS toast_reloptions "
4636                                                   "FROM pg_class "
4637                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4638                                                   "ORDER BY oid",
4639                                                   username_subquery,
4640                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4641         }
4642         else
4643         {
4644                 /*
4645                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4646                  * have a view by looking for a rule in pg_rewrite.
4647                  */
4648                 appendPQExpBuffer(query,
4649                                                   "SELECT "
4650                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4651                                                   "oid, relname, relacl, "
4652                                                   "CASE WHEN relhasrules and relkind = 'r' "
4653                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4654                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4655                                                   "THEN '%c'::\"char\" "
4656                                                   "ELSE relkind END AS relkind,"
4657                                                   "0::oid AS relnamespace, "
4658                                                   "(%s relowner) AS rolname, "
4659                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4660                                                   "relhasindex, relhasrules, "
4661                                                   "'t'::bool AS relhasoids, "
4662                                                   "0 as relfrozenxid, "
4663                                                   "0 AS toid, "
4664                                                   "0 AS tfrozenxid, "
4665                                                   "'p' AS relpersistence, 't' as relispopulated, "
4666                                                   "'d' AS relreplident, 0 AS relpages, "
4667                                                   "NULL AS reloftype, "
4668                                                   "NULL::oid AS owning_tab, "
4669                                                   "NULL::int4 AS owning_col, "
4670                                                   "NULL AS reltablespace, "
4671                                                   "NULL AS reloptions, "
4672                                                   "NULL AS toast_reloptions "
4673                                                   "FROM pg_class c "
4674                                                   "WHERE relkind IN ('%c', '%c') "
4675                                                   "ORDER BY oid",
4676                                                   RELKIND_VIEW,
4677                                                   username_subquery,
4678                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4679         }
4680
4681         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4682
4683         ntups = PQntuples(res);
4684
4685         *numTables = ntups;
4686
4687         /*
4688          * Extract data from result and lock dumpable tables.  We do the locking
4689          * before anything else, to minimize the window wherein a table could
4690          * disappear under us.
4691          *
4692          * Note that we have to save info about all tables here, even when dumping
4693          * only one, because we don't yet know which tables might be inheritance
4694          * ancestors of the target table.
4695          */
4696         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
4697
4698         i_reltableoid = PQfnumber(res, "tableoid");
4699         i_reloid = PQfnumber(res, "oid");
4700         i_relname = PQfnumber(res, "relname");
4701         i_relnamespace = PQfnumber(res, "relnamespace");
4702         i_relacl = PQfnumber(res, "relacl");
4703         i_relkind = PQfnumber(res, "relkind");
4704         i_rolname = PQfnumber(res, "rolname");
4705         i_relchecks = PQfnumber(res, "relchecks");
4706         i_relhastriggers = PQfnumber(res, "relhastriggers");
4707         i_relhasindex = PQfnumber(res, "relhasindex");
4708         i_relhasrules = PQfnumber(res, "relhasrules");
4709         i_relhasoids = PQfnumber(res, "relhasoids");
4710         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4711         i_toastoid = PQfnumber(res, "toid");
4712         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4713         i_relpersistence = PQfnumber(res, "relpersistence");
4714         i_relispopulated = PQfnumber(res, "relispopulated");
4715         i_relreplident = PQfnumber(res, "relreplident");
4716         i_relpages = PQfnumber(res, "relpages");
4717         i_owning_tab = PQfnumber(res, "owning_tab");
4718         i_owning_col = PQfnumber(res, "owning_col");
4719         i_reltablespace = PQfnumber(res, "reltablespace");
4720         i_reloptions = PQfnumber(res, "reloptions");
4721         i_checkoption = PQfnumber(res, "checkoption");
4722         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4723         i_reloftype = PQfnumber(res, "reloftype");
4724
4725         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4726         {
4727                 /*
4728                  * Arrange to fail instead of waiting forever for a table lock.
4729                  *
4730                  * NB: this coding assumes that the only queries issued within the
4731                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4732                  * applied to other things too.
4733                  */
4734                 resetPQExpBuffer(query);
4735                 appendPQExpBufferStr(query, "SET statement_timeout = ");
4736                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4737                 ExecuteSqlStatement(fout, query->data);
4738         }
4739
4740         for (i = 0; i < ntups; i++)
4741         {
4742                 tblinfo[i].dobj.objType = DO_TABLE;
4743                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4744                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4745                 AssignDumpId(&tblinfo[i].dobj);
4746                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4747                 tblinfo[i].dobj.namespace =
4748                         findNamespace(fout,
4749                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4750                                                   tblinfo[i].dobj.catId.oid);
4751                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4752                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4753                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4754                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4755                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4756                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4757                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4758                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4759                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
4760                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
4761                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
4762                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4763                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4764                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4765                 if (PQgetisnull(res, i, i_reloftype))
4766                         tblinfo[i].reloftype = NULL;
4767                 else
4768                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4769                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4770                 if (PQgetisnull(res, i, i_owning_tab))
4771                 {
4772                         tblinfo[i].owning_tab = InvalidOid;
4773                         tblinfo[i].owning_col = 0;
4774                 }
4775                 else
4776                 {
4777                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4778                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4779                 }
4780                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4781                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4782                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
4783                         tblinfo[i].checkoption = NULL;
4784                 else
4785                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
4786                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4787
4788                 /* other fields were zeroed above */
4789
4790                 /*
4791                  * Decide whether we want to dump this table.
4792                  */
4793                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4794                         tblinfo[i].dobj.dump = false;
4795                 else
4796                         selectDumpableTable(&tblinfo[i]);
4797                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4798
4799                 /*
4800                  * Read-lock target tables to make sure they aren't DROPPED or altered
4801                  * in schema before we get around to dumping them.
4802                  *
4803                  * Note that we don't explicitly lock parents of the target tables; we
4804                  * assume our lock on the child is enough to prevent schema
4805                  * alterations to parent tables.
4806                  *
4807                  * NOTE: it'd be kinda nice to lock other relations too, not only
4808                  * plain tables, but the backend doesn't presently allow that.
4809                  */
4810                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4811                 {
4812                         resetPQExpBuffer(query);
4813                         appendPQExpBuffer(query,
4814                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4815                                                           fmtQualifiedId(fout->remoteVersion,
4816                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4817                                                                                          tblinfo[i].dobj.name));
4818                         ExecuteSqlStatement(fout, query->data);
4819                 }
4820
4821                 /* Emit notice if join for owner failed */
4822                 if (strlen(tblinfo[i].rolname) == 0)
4823                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4824                                           tblinfo[i].dobj.name);
4825         }
4826
4827         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4828         {
4829                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4830         }
4831
4832         PQclear(res);
4833
4834         destroyPQExpBuffer(query);
4835
4836         return tblinfo;
4837 }
4838
4839 /*
4840  * getOwnedSeqs
4841  *        identify owned sequences and mark them as dumpable if owning table is
4842  *
4843  * We used to do this in getTables(), but it's better to do it after the
4844  * index used by findTableByOid() has been set up.
4845  */
4846 void
4847 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4848 {
4849         int                     i;
4850
4851         /*
4852          * Force sequences that are "owned" by table columns to be dumped whenever
4853          * their owning table is being dumped.
4854          */
4855         for (i = 0; i < numTables; i++)
4856         {
4857                 TableInfo  *seqinfo = &tblinfo[i];
4858                 TableInfo  *owning_tab;
4859
4860                 if (!OidIsValid(seqinfo->owning_tab))
4861                         continue;                       /* not an owned sequence */
4862                 if (seqinfo->dobj.dump)
4863                         continue;                       /* no need to search */
4864                 owning_tab = findTableByOid(seqinfo->owning_tab);
4865                 if (owning_tab && owning_tab->dobj.dump)
4866                 {
4867                         seqinfo->interesting = true;
4868                         seqinfo->dobj.dump = true;
4869                 }
4870         }
4871 }
4872
4873 /*
4874  * getInherits
4875  *        read all the inheritance information
4876  * from the system catalogs return them in the InhInfo* structure
4877  *
4878  * numInherits is set to the number of pairs read in
4879  */
4880 InhInfo *
4881 getInherits(Archive *fout, int *numInherits)
4882 {
4883         PGresult   *res;
4884         int                     ntups;
4885         int                     i;
4886         PQExpBuffer query = createPQExpBuffer();
4887         InhInfo    *inhinfo;
4888
4889         int                     i_inhrelid;
4890         int                     i_inhparent;
4891
4892         /* Make sure we are in proper schema */
4893         selectSourceSchema(fout, "pg_catalog");
4894
4895         /* find all the inheritance information */
4896
4897         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4898
4899         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4900
4901         ntups = PQntuples(res);
4902
4903         *numInherits = ntups;
4904
4905         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4906
4907         i_inhrelid = PQfnumber(res, "inhrelid");
4908         i_inhparent = PQfnumber(res, "inhparent");
4909
4910         for (i = 0; i < ntups; i++)
4911         {
4912                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4913                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4914         }
4915
4916         PQclear(res);
4917
4918         destroyPQExpBuffer(query);
4919
4920         return inhinfo;
4921 }
4922
4923 /*
4924  * getIndexes
4925  *        get information about every index on a dumpable table
4926  *
4927  * Note: index data is not returned directly to the caller, but it
4928  * does get entered into the DumpableObject tables.
4929  */
4930 void
4931 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4932 {
4933         int                     i,
4934                                 j;
4935         PQExpBuffer query = createPQExpBuffer();
4936         PGresult   *res;
4937         IndxInfo   *indxinfo;
4938         ConstraintInfo *constrinfo;
4939         int                     i_tableoid,
4940                                 i_oid,
4941                                 i_indexname,
4942                                 i_indexdef,
4943                                 i_indnkeys,
4944                                 i_indkey,
4945                                 i_indisclustered,
4946                                 i_indisreplident,
4947                                 i_contype,
4948                                 i_conname,
4949                                 i_condeferrable,
4950                                 i_condeferred,
4951                                 i_contableoid,
4952                                 i_conoid,
4953                                 i_condef,
4954                                 i_tablespace,
4955                                 i_options,
4956                                 i_relpages;
4957         int                     ntups;
4958
4959         for (i = 0; i < numTables; i++)
4960         {
4961                 TableInfo  *tbinfo = &tblinfo[i];
4962
4963                 /* Only plain tables and materialized views have indexes. */
4964                 if (tbinfo->relkind != RELKIND_RELATION &&
4965                         tbinfo->relkind != RELKIND_MATVIEW)
4966                         continue;
4967                 if (!tbinfo->hasindex)
4968                         continue;
4969
4970                 /* Ignore indexes of tables not to be dumped */
4971                 if (!tbinfo->dobj.dump)
4972                         continue;
4973
4974                 if (g_verbose)
4975                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4976                                           tbinfo->dobj.name);
4977
4978                 /* Make sure we are in proper schema so indexdef is right */
4979                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4980
4981                 /*
4982                  * The point of the messy-looking outer join is to find a constraint
4983                  * that is related by an internal dependency link to the index. If we
4984                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4985                  * assume an index won't have more than one internal dependency.
4986                  *
4987                  * As of 9.0 we don't need to look at pg_depend but can check for a
4988                  * match to pg_constraint.conindid.  The check on conrelid is
4989                  * redundant but useful because that column is indexed while conindid
4990                  * is not.
4991                  */
4992                 resetPQExpBuffer(query);
4993                 if (fout->remoteVersion >= 90400)
4994                 {
4995                         /*
4996                          * the test on indisready is necessary in 9.2, and harmless in
4997                          * earlier/later versions
4998                          */
4999                         appendPQExpBuffer(query,
5000                                                           "SELECT t.tableoid, t.oid, "
5001                                                           "t.relname AS indexname, "
5002                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5003                                                           "t.relnatts AS indnkeys, "
5004                                                           "i.indkey, i.indisclustered, "
5005                                                           "i.indisreplident, t.relpages, "
5006                                                           "c.contype, c.conname, "
5007                                                           "c.condeferrable, c.condeferred, "
5008                                                           "c.tableoid AS contableoid, "
5009                                                           "c.oid AS conoid, "
5010                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5011                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5012                                                         "array_to_string(t.reloptions, ', ') AS options "
5013                                                           "FROM pg_catalog.pg_index i "
5014                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5015                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5016                                                           "ON (i.indrelid = c.conrelid AND "
5017                                                           "i.indexrelid = c.conindid AND "
5018                                                           "c.contype IN ('p','u','x')) "
5019                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5020                                                           "AND i.indisvalid AND i.indisready "
5021                                                           "ORDER BY indexname",
5022                                                           tbinfo->dobj.catId.oid);
5023                 }
5024                 else if (fout->remoteVersion >= 90000)
5025                 {
5026                         /*
5027                          * the test on indisready is necessary in 9.2, and harmless in
5028                          * earlier/later versions
5029                          */
5030                         appendPQExpBuffer(query,
5031                                                           "SELECT t.tableoid, t.oid, "
5032                                                           "t.relname AS indexname, "
5033                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5034                                                           "t.relnatts AS indnkeys, "
5035                                                           "i.indkey, i.indisclustered, "
5036                                                           "false AS indisreplident, t.relpages, "
5037                                                           "c.contype, c.conname, "
5038                                                           "c.condeferrable, c.condeferred, "
5039                                                           "c.tableoid AS contableoid, "
5040                                                           "c.oid AS conoid, "
5041                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5042                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5043                                                         "array_to_string(t.reloptions, ', ') AS options "
5044                                                           "FROM pg_catalog.pg_index i "
5045                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5046                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5047                                                           "ON (i.indrelid = c.conrelid AND "
5048                                                           "i.indexrelid = c.conindid AND "
5049                                                           "c.contype IN ('p','u','x')) "
5050                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5051                                                           "AND i.indisvalid AND i.indisready "
5052                                                           "ORDER BY indexname",
5053                                                           tbinfo->dobj.catId.oid);
5054                 }
5055                 else if (fout->remoteVersion >= 80200)
5056                 {
5057                         appendPQExpBuffer(query,
5058                                                           "SELECT t.tableoid, t.oid, "
5059                                                           "t.relname AS indexname, "
5060                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5061                                                           "t.relnatts AS indnkeys, "
5062                                                           "i.indkey, i.indisclustered, "
5063                                                           "false AS indisreplident, t.relpages, "
5064                                                           "c.contype, c.conname, "
5065                                                           "c.condeferrable, c.condeferred, "
5066                                                           "c.tableoid AS contableoid, "
5067                                                           "c.oid AS conoid, "
5068                                                           "null AS condef, "
5069                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5070                                                         "array_to_string(t.reloptions, ', ') AS options "
5071                                                           "FROM pg_catalog.pg_index i "
5072                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5073                                                           "LEFT JOIN pg_catalog.pg_depend d "
5074                                                           "ON (d.classid = t.tableoid "
5075                                                           "AND d.objid = t.oid "
5076                                                           "AND d.deptype = 'i') "
5077                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5078                                                           "ON (d.refclassid = c.tableoid "
5079                                                           "AND d.refobjid = c.oid) "
5080                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5081                                                           "AND i.indisvalid "
5082                                                           "ORDER BY indexname",
5083                                                           tbinfo->dobj.catId.oid);
5084                 }
5085                 else if (fout->remoteVersion >= 80000)
5086                 {
5087                         appendPQExpBuffer(query,
5088                                                           "SELECT t.tableoid, t.oid, "
5089                                                           "t.relname AS indexname, "
5090                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5091                                                           "t.relnatts AS indnkeys, "
5092                                                           "i.indkey, i.indisclustered, "
5093                                                           "false AS indisreplident, t.relpages, "
5094                                                           "c.contype, c.conname, "
5095                                                           "c.condeferrable, c.condeferred, "
5096                                                           "c.tableoid AS contableoid, "
5097                                                           "c.oid AS conoid, "
5098                                                           "null AS condef, "
5099                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5100                                                           "null AS options "
5101                                                           "FROM pg_catalog.pg_index i "
5102                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5103                                                           "LEFT JOIN pg_catalog.pg_depend d "
5104                                                           "ON (d.classid = t.tableoid "
5105                                                           "AND d.objid = t.oid "
5106                                                           "AND d.deptype = 'i') "
5107                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5108                                                           "ON (d.refclassid = c.tableoid "
5109                                                           "AND d.refobjid = c.oid) "
5110                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5111                                                           "ORDER BY indexname",
5112                                                           tbinfo->dobj.catId.oid);
5113                 }
5114                 else if (fout->remoteVersion >= 70300)
5115                 {
5116                         appendPQExpBuffer(query,
5117                                                           "SELECT t.tableoid, t.oid, "
5118                                                           "t.relname AS indexname, "
5119                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5120                                                           "t.relnatts AS indnkeys, "
5121                                                           "i.indkey, i.indisclustered, "
5122                                                           "false AS indisreplident, t.relpages, "
5123                                                           "c.contype, c.conname, "
5124                                                           "c.condeferrable, c.condeferred, "
5125                                                           "c.tableoid AS contableoid, "
5126                                                           "c.oid AS conoid, "
5127                                                           "null AS condef, "
5128                                                           "NULL AS tablespace, "
5129                                                           "null AS options "
5130                                                           "FROM pg_catalog.pg_index i "
5131                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5132                                                           "LEFT JOIN pg_catalog.pg_depend d "
5133                                                           "ON (d.classid = t.tableoid "
5134                                                           "AND d.objid = t.oid "
5135                                                           "AND d.deptype = 'i') "
5136                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5137                                                           "ON (d.refclassid = c.tableoid "
5138                                                           "AND d.refobjid = c.oid) "
5139                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5140                                                           "ORDER BY indexname",
5141                                                           tbinfo->dobj.catId.oid);
5142                 }
5143                 else if (fout->remoteVersion >= 70100)
5144                 {
5145                         appendPQExpBuffer(query,
5146                                                           "SELECT t.tableoid, t.oid, "
5147                                                           "t.relname AS indexname, "
5148                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5149                                                           "t.relnatts AS indnkeys, "
5150                                                           "i.indkey, false AS indisclustered, "
5151                                                           "false AS indisreplident, t.relpages, "
5152                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5153                                                           "ELSE '0'::char END AS contype, "
5154                                                           "t.relname AS conname, "
5155                                                           "false AS condeferrable, "
5156                                                           "false AS condeferred, "
5157                                                           "0::oid AS contableoid, "
5158                                                           "t.oid AS conoid, "
5159                                                           "null AS condef, "
5160                                                           "NULL AS tablespace, "
5161                                                           "null AS options "
5162                                                           "FROM pg_index i, pg_class t "
5163                                                           "WHERE t.oid = i.indexrelid "
5164                                                           "AND i.indrelid = '%u'::oid "
5165                                                           "ORDER BY indexname",
5166                                                           tbinfo->dobj.catId.oid);
5167                 }
5168                 else
5169                 {
5170                         appendPQExpBuffer(query,
5171                                                           "SELECT "
5172                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5173                                                           "t.oid, "
5174                                                           "t.relname AS indexname, "
5175                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5176                                                           "t.relnatts AS indnkeys, "
5177                                                           "i.indkey, false AS indisclustered, "
5178                                                           "false AS indisreplident, t.relpages, "
5179                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5180                                                           "ELSE '0'::char END AS contype, "
5181                                                           "t.relname AS conname, "
5182                                                           "false AS condeferrable, "
5183                                                           "false AS condeferred, "
5184                                                           "0::oid AS contableoid, "
5185                                                           "t.oid AS conoid, "
5186                                                           "null AS condef, "
5187                                                           "NULL AS tablespace, "
5188                                                           "null AS options "
5189                                                           "FROM pg_index i, pg_class t "
5190                                                           "WHERE t.oid = i.indexrelid "
5191                                                           "AND i.indrelid = '%u'::oid "
5192                                                           "ORDER BY indexname",
5193                                                           tbinfo->dobj.catId.oid);
5194                 }
5195
5196                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5197
5198                 ntups = PQntuples(res);
5199
5200                 i_tableoid = PQfnumber(res, "tableoid");
5201                 i_oid = PQfnumber(res, "oid");
5202                 i_indexname = PQfnumber(res, "indexname");
5203                 i_indexdef = PQfnumber(res, "indexdef");
5204                 i_indnkeys = PQfnumber(res, "indnkeys");
5205                 i_indkey = PQfnumber(res, "indkey");
5206                 i_indisclustered = PQfnumber(res, "indisclustered");
5207                 i_indisreplident = PQfnumber(res, "indisreplident");
5208                 i_relpages = PQfnumber(res, "relpages");
5209                 i_contype = PQfnumber(res, "contype");
5210                 i_conname = PQfnumber(res, "conname");
5211                 i_condeferrable = PQfnumber(res, "condeferrable");
5212                 i_condeferred = PQfnumber(res, "condeferred");
5213                 i_contableoid = PQfnumber(res, "contableoid");
5214                 i_conoid = PQfnumber(res, "conoid");
5215                 i_condef = PQfnumber(res, "condef");
5216                 i_tablespace = PQfnumber(res, "tablespace");
5217                 i_options = PQfnumber(res, "options");
5218
5219                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5220                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5221
5222                 for (j = 0; j < ntups; j++)
5223                 {
5224                         char            contype;
5225
5226                         indxinfo[j].dobj.objType = DO_INDEX;
5227                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5228                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5229                         AssignDumpId(&indxinfo[j].dobj);
5230                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5231                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5232                         indxinfo[j].indextable = tbinfo;
5233                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5234                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5235                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5236                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5237
5238                         /*
5239                          * In pre-7.4 releases, indkeys may contain more entries than
5240                          * indnkeys says (since indnkeys will be 1 for a functional
5241                          * index).      We don't actually care about this case since we don't
5242                          * examine indkeys except for indexes associated with PRIMARY and
5243                          * UNIQUE constraints, which are never functional indexes. But we
5244                          * have to allocate enough space to keep parseOidArray from
5245                          * complaining.
5246                          */
5247                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5248                         parseOidArray(PQgetvalue(res, j, i_indkey),
5249                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5250                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5251                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
5252                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5253                         contype = *(PQgetvalue(res, j, i_contype));
5254
5255                         if (contype == 'p' || contype == 'u' || contype == 'x')
5256                         {
5257                                 /*
5258                                  * If we found a constraint matching the index, create an
5259                                  * entry for it.
5260                                  *
5261                                  * In a pre-7.3 database, we take this path iff the index was
5262                                  * marked indisprimary.
5263                                  */
5264                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5265                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5266                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5267                                 AssignDumpId(&constrinfo[j].dobj);
5268                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5269                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5270                                 constrinfo[j].contable = tbinfo;
5271                                 constrinfo[j].condomain = NULL;
5272                                 constrinfo[j].contype = contype;
5273                                 if (contype == 'x')
5274                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5275                                 else
5276                                         constrinfo[j].condef = NULL;
5277                                 constrinfo[j].confrelid = InvalidOid;
5278                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5279                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5280                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5281                                 constrinfo[j].conislocal = true;
5282                                 constrinfo[j].separate = true;
5283
5284                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5285
5286                                 /* If pre-7.3 DB, better make sure table comes first */
5287                                 addObjectDependency(&constrinfo[j].dobj,
5288                                                                         tbinfo->dobj.dumpId);
5289                         }
5290                         else
5291                         {
5292                                 /* Plain secondary index */
5293                                 indxinfo[j].indexconstraint = 0;
5294                         }
5295                 }
5296
5297                 PQclear(res);
5298         }
5299
5300         destroyPQExpBuffer(query);
5301 }
5302
5303 /*
5304  * getConstraints
5305  *
5306  * Get info about constraints on dumpable tables.
5307  *
5308  * Currently handles foreign keys only.
5309  * Unique and primary key constraints are handled with indexes,
5310  * while check constraints are processed in getTableAttrs().
5311  */
5312 void
5313 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5314 {
5315         int                     i,
5316                                 j;
5317         ConstraintInfo *constrinfo;
5318         PQExpBuffer query;
5319         PGresult   *res;
5320         int                     i_contableoid,
5321                                 i_conoid,
5322                                 i_conname,
5323                                 i_confrelid,
5324                                 i_condef;
5325         int                     ntups;
5326
5327         /* pg_constraint was created in 7.3, so nothing to do if older */
5328         if (fout->remoteVersion < 70300)
5329                 return;
5330
5331         query = createPQExpBuffer();
5332
5333         for (i = 0; i < numTables; i++)
5334         {
5335                 TableInfo  *tbinfo = &tblinfo[i];
5336
5337                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5338                         continue;
5339
5340                 if (g_verbose)
5341                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
5342                                           tbinfo->dobj.name);
5343
5344                 /*
5345                  * select table schema to ensure constraint expr is qualified if
5346                  * needed
5347                  */
5348                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5349
5350                 resetPQExpBuffer(query);
5351                 appendPQExpBuffer(query,
5352                                                   "SELECT tableoid, oid, conname, confrelid, "
5353                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5354                                                   "FROM pg_catalog.pg_constraint "
5355                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5356                                                   "AND contype = 'f'",
5357                                                   tbinfo->dobj.catId.oid);
5358                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5359
5360                 ntups = PQntuples(res);
5361
5362                 i_contableoid = PQfnumber(res, "tableoid");
5363                 i_conoid = PQfnumber(res, "oid");
5364                 i_conname = PQfnumber(res, "conname");
5365                 i_confrelid = PQfnumber(res, "confrelid");
5366                 i_condef = PQfnumber(res, "condef");
5367
5368                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5369
5370                 for (j = 0; j < ntups; j++)
5371                 {
5372                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5373                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5374                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5375                         AssignDumpId(&constrinfo[j].dobj);
5376                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5377                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5378                         constrinfo[j].contable = tbinfo;
5379                         constrinfo[j].condomain = NULL;
5380                         constrinfo[j].contype = 'f';
5381                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5382                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5383                         constrinfo[j].conindex = 0;
5384                         constrinfo[j].condeferrable = false;
5385                         constrinfo[j].condeferred = false;
5386                         constrinfo[j].conislocal = true;
5387                         constrinfo[j].separate = true;
5388                 }
5389
5390                 PQclear(res);
5391         }
5392
5393         destroyPQExpBuffer(query);
5394 }
5395
5396 /*
5397  * getDomainConstraints
5398  *
5399  * Get info about constraints on a domain.
5400  */
5401 static void
5402 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5403 {
5404         int                     i;
5405         ConstraintInfo *constrinfo;
5406         PQExpBuffer query;
5407         PGresult   *res;
5408         int                     i_tableoid,
5409                                 i_oid,
5410                                 i_conname,
5411                                 i_consrc;
5412         int                     ntups;
5413
5414         /* pg_constraint was created in 7.3, so nothing to do if older */
5415         if (fout->remoteVersion < 70300)
5416                 return;
5417
5418         /*
5419          * select appropriate schema to ensure names in constraint are properly
5420          * qualified
5421          */
5422         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5423
5424         query = createPQExpBuffer();
5425
5426         if (fout->remoteVersion >= 90100)
5427                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5428                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5429                                                   "convalidated "
5430                                                   "FROM pg_catalog.pg_constraint "
5431                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5432                                                   "ORDER BY conname",
5433                                                   tyinfo->dobj.catId.oid);
5434
5435         else if (fout->remoteVersion >= 70400)
5436                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5437                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5438                                                   "true as convalidated "
5439                                                   "FROM pg_catalog.pg_constraint "
5440                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5441                                                   "ORDER BY conname",
5442                                                   tyinfo->dobj.catId.oid);
5443         else
5444                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5445                                                   "'CHECK (' || consrc || ')' AS consrc, "
5446                                                   "true as convalidated "
5447                                                   "FROM pg_catalog.pg_constraint "
5448                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5449                                                   "ORDER BY conname",
5450                                                   tyinfo->dobj.catId.oid);
5451
5452         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5453
5454         ntups = PQntuples(res);
5455
5456         i_tableoid = PQfnumber(res, "tableoid");
5457         i_oid = PQfnumber(res, "oid");
5458         i_conname = PQfnumber(res, "conname");
5459         i_consrc = PQfnumber(res, "consrc");
5460
5461         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5462
5463         tyinfo->nDomChecks = ntups;
5464         tyinfo->domChecks = constrinfo;
5465
5466         for (i = 0; i < ntups; i++)
5467         {
5468                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5469
5470                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5471                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5472                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5473                 AssignDumpId(&constrinfo[i].dobj);
5474                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5475                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5476                 constrinfo[i].contable = NULL;
5477                 constrinfo[i].condomain = tyinfo;
5478                 constrinfo[i].contype = 'c';
5479                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5480                 constrinfo[i].confrelid = InvalidOid;
5481                 constrinfo[i].conindex = 0;
5482                 constrinfo[i].condeferrable = false;
5483                 constrinfo[i].condeferred = false;
5484                 constrinfo[i].conislocal = true;
5485
5486                 constrinfo[i].separate = !validated;
5487
5488                 /*
5489                  * Make the domain depend on the constraint, ensuring it won't be
5490                  * output till any constraint dependencies are OK.      If the constraint
5491                  * has not been validated, it's going to be dumped after the domain
5492                  * anyway, so this doesn't matter.
5493                  */
5494                 if (validated)
5495                         addObjectDependency(&tyinfo->dobj,
5496                                                                 constrinfo[i].dobj.dumpId);
5497         }
5498
5499         PQclear(res);
5500
5501         destroyPQExpBuffer(query);
5502 }
5503
5504 /*
5505  * getRules
5506  *        get basic information about every rule in the system
5507  *
5508  * numRules is set to the number of rules read in
5509  */
5510 RuleInfo *
5511 getRules(Archive *fout, int *numRules)
5512 {
5513         PGresult   *res;
5514         int                     ntups;
5515         int                     i;
5516         PQExpBuffer query = createPQExpBuffer();
5517         RuleInfo   *ruleinfo;
5518         int                     i_tableoid;
5519         int                     i_oid;
5520         int                     i_rulename;
5521         int                     i_ruletable;
5522         int                     i_ev_type;
5523         int                     i_is_instead;
5524         int                     i_ev_enabled;
5525
5526         /* Make sure we are in proper schema */
5527         selectSourceSchema(fout, "pg_catalog");
5528
5529         if (fout->remoteVersion >= 80300)
5530         {
5531                 appendPQExpBufferStr(query, "SELECT "
5532                                                          "tableoid, oid, rulename, "
5533                                                          "ev_class AS ruletable, ev_type, is_instead, "
5534                                                          "ev_enabled "
5535                                                          "FROM pg_rewrite "
5536                                                          "ORDER BY oid");
5537         }
5538         else if (fout->remoteVersion >= 70100)
5539         {
5540                 appendPQExpBufferStr(query, "SELECT "
5541                                                          "tableoid, oid, rulename, "
5542                                                          "ev_class AS ruletable, ev_type, is_instead, "
5543                                                          "'O'::char AS ev_enabled "
5544                                                          "FROM pg_rewrite "
5545                                                          "ORDER BY oid");
5546         }
5547         else
5548         {
5549                 appendPQExpBufferStr(query, "SELECT "
5550                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5551                                                          "oid, rulename, "
5552                                                          "ev_class AS ruletable, ev_type, is_instead, "
5553                                                          "'O'::char AS ev_enabled "
5554                                                          "FROM pg_rewrite "
5555                                                          "ORDER BY oid");
5556         }
5557
5558         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5559
5560         ntups = PQntuples(res);
5561
5562         *numRules = ntups;
5563
5564         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5565
5566         i_tableoid = PQfnumber(res, "tableoid");
5567         i_oid = PQfnumber(res, "oid");
5568         i_rulename = PQfnumber(res, "rulename");
5569         i_ruletable = PQfnumber(res, "ruletable");
5570         i_ev_type = PQfnumber(res, "ev_type");
5571         i_is_instead = PQfnumber(res, "is_instead");
5572         i_ev_enabled = PQfnumber(res, "ev_enabled");
5573
5574         for (i = 0; i < ntups; i++)
5575         {
5576                 Oid                     ruletableoid;
5577
5578                 ruleinfo[i].dobj.objType = DO_RULE;
5579                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5580                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5581                 AssignDumpId(&ruleinfo[i].dobj);
5582                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5583                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5584                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5585                 if (ruleinfo[i].ruletable == NULL)
5586                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5587                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5588                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5589                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5590                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5591                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5592                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5593                 if (ruleinfo[i].ruletable)
5594                 {
5595                         /*
5596                          * If the table is a view or materialized view, force its ON
5597                          * SELECT rule to be sorted before the view itself --- this
5598                          * ensures that any dependencies for the rule affect the table's
5599                          * positioning. Other rules are forced to appear after their
5600                          * table.
5601                          */
5602                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5603                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5604                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5605                         {
5606                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5607                                                                         ruleinfo[i].dobj.dumpId);
5608                                 /* We'll merge the rule into CREATE VIEW, if possible */
5609                                 ruleinfo[i].separate = false;
5610                         }
5611                         else
5612                         {
5613                                 addObjectDependency(&ruleinfo[i].dobj,
5614                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5615                                 ruleinfo[i].separate = true;
5616                         }
5617                 }
5618                 else
5619                         ruleinfo[i].separate = true;
5620
5621                 /*
5622                  * If we're forced to break a dependency loop by dumping a view as a
5623                  * table and separate _RETURN rule, we'll move the view's reloptions
5624                  * to the rule.  (This is necessary because tables and views have
5625                  * different valid reloptions, so we can't apply the options until the
5626                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5627                  * NULL.
5628                  */
5629                 ruleinfo[i].reloptions = NULL;
5630         }
5631
5632         PQclear(res);
5633
5634         destroyPQExpBuffer(query);
5635
5636         return ruleinfo;
5637 }
5638
5639 /*
5640  * getTriggers
5641  *        get information about every trigger on a dumpable table
5642  *
5643  * Note: trigger data is not returned directly to the caller, but it
5644  * does get entered into the DumpableObject tables.
5645  */
5646 void
5647 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5648 {
5649         int                     i,
5650                                 j;
5651         PQExpBuffer query = createPQExpBuffer();
5652         PGresult   *res;
5653         TriggerInfo *tginfo;
5654         int                     i_tableoid,
5655                                 i_oid,
5656                                 i_tgname,
5657                                 i_tgfname,
5658                                 i_tgtype,
5659                                 i_tgnargs,
5660                                 i_tgargs,
5661                                 i_tgisconstraint,
5662                                 i_tgconstrname,
5663                                 i_tgconstrrelid,
5664                                 i_tgconstrrelname,
5665                                 i_tgenabled,
5666                                 i_tgdeferrable,
5667                                 i_tginitdeferred,
5668                                 i_tgdef;
5669         int                     ntups;
5670
5671         for (i = 0; i < numTables; i++)
5672         {
5673                 TableInfo  *tbinfo = &tblinfo[i];
5674
5675                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5676                         continue;
5677
5678                 if (g_verbose)
5679                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5680                                           tbinfo->dobj.name);
5681
5682                 /*
5683                  * select table schema to ensure regproc name is qualified if needed
5684                  */
5685                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5686
5687                 resetPQExpBuffer(query);
5688                 if (fout->remoteVersion >= 90000)
5689                 {
5690                         /*
5691                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5692                          * could result in non-forward-compatible dumps of WHEN clauses
5693                          * due to under-parenthesization.
5694                          */
5695                         appendPQExpBuffer(query,
5696                                                           "SELECT tgname, "
5697                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5698                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5699                                                           "tgenabled, tableoid, oid "
5700                                                           "FROM pg_catalog.pg_trigger t "
5701                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5702                                                           "AND NOT tgisinternal",
5703                                                           tbinfo->dobj.catId.oid);
5704                 }
5705                 else if (fout->remoteVersion >= 80300)
5706                 {
5707                         /*
5708                          * We ignore triggers that are tied to a foreign-key constraint
5709                          */
5710                         appendPQExpBuffer(query,
5711                                                           "SELECT tgname, "
5712                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5713                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5714                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5715                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5716                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5717                                                           "FROM pg_catalog.pg_trigger t "
5718                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5719                                                           "AND tgconstraint = 0",
5720                                                           tbinfo->dobj.catId.oid);
5721                 }
5722                 else if (fout->remoteVersion >= 70300)
5723                 {
5724                         /*
5725                          * We ignore triggers that are tied to a foreign-key constraint,
5726                          * but in these versions we have to grovel through pg_constraint
5727                          * to find out
5728                          */
5729                         appendPQExpBuffer(query,
5730                                                           "SELECT tgname, "
5731                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5732                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5733                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5734                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5735                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5736                                                           "FROM pg_catalog.pg_trigger t "
5737                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5738                                                           "AND (NOT tgisconstraint "
5739                                                           " OR NOT EXISTS"
5740                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5741                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5742                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5743                                                           tbinfo->dobj.catId.oid);
5744                 }
5745                 else if (fout->remoteVersion >= 70100)
5746                 {
5747                         appendPQExpBuffer(query,
5748                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5749                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5750                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5751                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5752                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5753                                                           "             AS tgconstrrelname "
5754                                                           "FROM pg_trigger "
5755                                                           "WHERE tgrelid = '%u'::oid",
5756                                                           tbinfo->dobj.catId.oid);
5757                 }
5758                 else
5759                 {
5760                         appendPQExpBuffer(query,
5761                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5762                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5763                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5764                                                           "tgconstrrelid, tginitdeferred, "
5765                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5766                                                           "oid, "
5767                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5768                                                           "             AS tgconstrrelname "
5769                                                           "FROM pg_trigger "
5770                                                           "WHERE tgrelid = '%u'::oid",
5771                                                           tbinfo->dobj.catId.oid);
5772                 }
5773                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5774
5775                 ntups = PQntuples(res);
5776
5777                 i_tableoid = PQfnumber(res, "tableoid");
5778                 i_oid = PQfnumber(res, "oid");
5779                 i_tgname = PQfnumber(res, "tgname");
5780                 i_tgfname = PQfnumber(res, "tgfname");
5781                 i_tgtype = PQfnumber(res, "tgtype");
5782                 i_tgnargs = PQfnumber(res, "tgnargs");
5783                 i_tgargs = PQfnumber(res, "tgargs");
5784                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5785                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5786                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5787                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5788                 i_tgenabled = PQfnumber(res, "tgenabled");
5789                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5790                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5791                 i_tgdef = PQfnumber(res, "tgdef");
5792
5793                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5794
5795                 for (j = 0; j < ntups; j++)
5796                 {
5797                         tginfo[j].dobj.objType = DO_TRIGGER;
5798                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5799                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5800                         AssignDumpId(&tginfo[j].dobj);
5801                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5802                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5803                         tginfo[j].tgtable = tbinfo;
5804                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5805                         if (i_tgdef >= 0)
5806                         {
5807                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5808
5809                                 /* remaining fields are not valid if we have tgdef */
5810                                 tginfo[j].tgfname = NULL;
5811                                 tginfo[j].tgtype = 0;
5812                                 tginfo[j].tgnargs = 0;
5813                                 tginfo[j].tgargs = NULL;
5814                                 tginfo[j].tgisconstraint = false;
5815                                 tginfo[j].tgdeferrable = false;
5816                                 tginfo[j].tginitdeferred = false;
5817                                 tginfo[j].tgconstrname = NULL;
5818                                 tginfo[j].tgconstrrelid = InvalidOid;
5819                                 tginfo[j].tgconstrrelname = NULL;
5820                         }
5821                         else
5822                         {
5823                                 tginfo[j].tgdef = NULL;
5824
5825                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5826                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5827                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5828                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5829                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5830                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5831                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5832
5833                                 if (tginfo[j].tgisconstraint)
5834                                 {
5835                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5836                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5837                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5838                                         {
5839                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5840                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5841                                                                                   tginfo[j].dobj.name,
5842                                                                                   tbinfo->dobj.name,
5843                                                                                   tginfo[j].tgconstrrelid);
5844                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5845                                         }
5846                                         else
5847                                                 tginfo[j].tgconstrrelname = NULL;
5848                                 }
5849                                 else
5850                                 {
5851                                         tginfo[j].tgconstrname = NULL;
5852                                         tginfo[j].tgconstrrelid = InvalidOid;
5853                                         tginfo[j].tgconstrrelname = NULL;
5854                                 }
5855                         }
5856                 }
5857
5858                 PQclear(res);
5859         }
5860
5861         destroyPQExpBuffer(query);
5862 }
5863
5864 /*
5865  * getEventTriggers
5866  *        get information about event triggers
5867  */
5868 EventTriggerInfo *
5869 getEventTriggers(Archive *fout, int *numEventTriggers)
5870 {
5871         int                     i;
5872         PQExpBuffer query;
5873         PGresult   *res;
5874         EventTriggerInfo *evtinfo;
5875         int                     i_tableoid,
5876                                 i_oid,
5877                                 i_evtname,
5878                                 i_evtevent,
5879                                 i_evtowner,
5880                                 i_evttags,
5881                                 i_evtfname,
5882                                 i_evtenabled;
5883         int                     ntups;
5884
5885         /* Before 9.3, there are no event triggers */
5886         if (fout->remoteVersion < 90300)
5887         {
5888                 *numEventTriggers = 0;
5889                 return NULL;
5890         }
5891
5892         query = createPQExpBuffer();
5893
5894         /* Make sure we are in proper schema */
5895         selectSourceSchema(fout, "pg_catalog");
5896
5897         appendPQExpBuffer(query,
5898                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5899                                           "evtevent, (%s evtowner) AS evtowner, "
5900                                           "array_to_string(array("
5901                                           "select quote_literal(x) "
5902                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5903                                           "e.evtfoid::regproc as evtfname "
5904                                           "FROM pg_event_trigger e "
5905                                           "ORDER BY e.oid",
5906                                           username_subquery);
5907
5908         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5909
5910         ntups = PQntuples(res);
5911
5912         *numEventTriggers = ntups;
5913
5914         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5915
5916         i_tableoid = PQfnumber(res, "tableoid");
5917         i_oid = PQfnumber(res, "oid");
5918         i_evtname = PQfnumber(res, "evtname");
5919         i_evtevent = PQfnumber(res, "evtevent");
5920         i_evtowner = PQfnumber(res, "evtowner");
5921         i_evttags = PQfnumber(res, "evttags");
5922         i_evtfname = PQfnumber(res, "evtfname");
5923         i_evtenabled = PQfnumber(res, "evtenabled");
5924
5925         for (i = 0; i < ntups; i++)
5926         {
5927                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5928                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5929                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5930                 AssignDumpId(&evtinfo[i].dobj);
5931                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5932                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5933                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5934                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5935                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5936                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5937                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5938         }
5939
5940         PQclear(res);
5941
5942         destroyPQExpBuffer(query);
5943
5944         return evtinfo;
5945 }
5946
5947 /*
5948  * getProcLangs
5949  *        get basic information about every procedural language in the system
5950  *
5951  * numProcLangs is set to the number of langs read in
5952  *
5953  * NB: this must run after getFuncs() because we assume we can do
5954  * findFuncByOid().
5955  */
5956 ProcLangInfo *
5957 getProcLangs(Archive *fout, int *numProcLangs)
5958 {
5959         PGresult   *res;
5960         int                     ntups;
5961         int                     i;
5962         PQExpBuffer query = createPQExpBuffer();
5963         ProcLangInfo *planginfo;
5964         int                     i_tableoid;
5965         int                     i_oid;
5966         int                     i_lanname;
5967         int                     i_lanpltrusted;
5968         int                     i_lanplcallfoid;
5969         int                     i_laninline;
5970         int                     i_lanvalidator;
5971         int                     i_lanacl;
5972         int                     i_lanowner;
5973
5974         /* Make sure we are in proper schema */
5975         selectSourceSchema(fout, "pg_catalog");
5976
5977         if (fout->remoteVersion >= 90000)
5978         {
5979                 /* pg_language has a laninline column */
5980                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5981                                                   "lanname, lanpltrusted, lanplcallfoid, "
5982                                                   "laninline, lanvalidator,  lanacl, "
5983                                                   "(%s lanowner) AS lanowner "
5984                                                   "FROM pg_language "
5985                                                   "WHERE lanispl "
5986                                                   "ORDER BY oid",
5987                                                   username_subquery);
5988         }
5989         else if (fout->remoteVersion >= 80300)
5990         {
5991                 /* pg_language has a lanowner column */
5992                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5993                                                   "lanname, lanpltrusted, lanplcallfoid, "
5994                                                   "lanvalidator,  lanacl, "
5995                                                   "(%s lanowner) AS lanowner "
5996                                                   "FROM pg_language "
5997                                                   "WHERE lanispl "
5998                                                   "ORDER BY oid",
5999                                                   username_subquery);
6000         }
6001         else if (fout->remoteVersion >= 80100)
6002         {
6003                 /* Languages are owned by the bootstrap superuser, OID 10 */
6004                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6005                                                   "(%s '10') AS lanowner "
6006                                                   "FROM pg_language "
6007                                                   "WHERE lanispl "
6008                                                   "ORDER BY oid",
6009                                                   username_subquery);
6010         }
6011         else if (fout->remoteVersion >= 70400)
6012         {
6013                 /* Languages are owned by the bootstrap superuser, sysid 1 */
6014                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6015                                                   "(%s '1') AS lanowner "
6016                                                   "FROM pg_language "
6017                                                   "WHERE lanispl "
6018                                                   "ORDER BY oid",
6019                                                   username_subquery);
6020         }
6021         else if (fout->remoteVersion >= 70100)
6022         {
6023                 /* No clear notion of an owner at all before 7.4 ... */
6024                 appendPQExpBufferStr(query, "SELECT tableoid, oid, * FROM pg_language "
6025                                                          "WHERE lanispl "
6026                                                          "ORDER BY oid");
6027         }
6028         else
6029         {
6030                 appendPQExpBufferStr(query, "SELECT "
6031                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
6032                                                          "oid, * FROM pg_language "
6033                                                          "WHERE lanispl "
6034                                                          "ORDER BY oid");
6035         }
6036
6037         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6038
6039         ntups = PQntuples(res);
6040
6041         *numProcLangs = ntups;
6042
6043         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
6044
6045         i_tableoid = PQfnumber(res, "tableoid");
6046         i_oid = PQfnumber(res, "oid");
6047         i_lanname = PQfnumber(res, "lanname");
6048         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
6049         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
6050         /* these may fail and return -1: */
6051         i_laninline = PQfnumber(res, "laninline");
6052         i_lanvalidator = PQfnumber(res, "lanvalidator");
6053         i_lanacl = PQfnumber(res, "lanacl");
6054         i_lanowner = PQfnumber(res, "lanowner");
6055
6056         for (i = 0; i < ntups; i++)
6057         {
6058                 planginfo[i].dobj.objType = DO_PROCLANG;
6059                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6060                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6061                 AssignDumpId(&planginfo[i].dobj);
6062
6063                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
6064                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
6065                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
6066                 if (i_laninline >= 0)
6067                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
6068                 else
6069                         planginfo[i].laninline = InvalidOid;
6070                 if (i_lanvalidator >= 0)
6071                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
6072                 else
6073                         planginfo[i].lanvalidator = InvalidOid;
6074                 if (i_lanacl >= 0)
6075                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
6076                 else
6077                         planginfo[i].lanacl = pg_strdup("{=U}");
6078                 if (i_lanowner >= 0)
6079                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
6080                 else
6081                         planginfo[i].lanowner = pg_strdup("");
6082
6083                 if (fout->remoteVersion < 70300)
6084                 {
6085                         /*
6086                          * We need to make a dependency to ensure the function will be
6087                          * dumped first.  (In 7.3 and later the regular dependency
6088                          * mechanism will handle this for us.)
6089                          */
6090                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
6091
6092                         if (funcInfo)
6093                                 addObjectDependency(&planginfo[i].dobj,
6094                                                                         funcInfo->dobj.dumpId);
6095                 }
6096         }
6097
6098         PQclear(res);
6099
6100         destroyPQExpBuffer(query);
6101
6102         return planginfo;
6103 }
6104
6105 /*
6106  * getCasts
6107  *        get basic information about every cast in the system
6108  *
6109  * numCasts is set to the number of casts read in
6110  */
6111 CastInfo *
6112 getCasts(Archive *fout, int *numCasts)
6113 {
6114         PGresult   *res;
6115         int                     ntups;
6116         int                     i;
6117         PQExpBuffer query = createPQExpBuffer();
6118         CastInfo   *castinfo;
6119         int                     i_tableoid;
6120         int                     i_oid;
6121         int                     i_castsource;
6122         int                     i_casttarget;
6123         int                     i_castfunc;
6124         int                     i_castcontext;
6125         int                     i_castmethod;
6126
6127         /* Make sure we are in proper schema */
6128         selectSourceSchema(fout, "pg_catalog");
6129
6130         if (fout->remoteVersion >= 80400)
6131         {
6132                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
6133                                                          "castsource, casttarget, castfunc, castcontext, "
6134                                                          "castmethod "
6135                                                          "FROM pg_cast ORDER BY 3,4");
6136         }
6137         else if (fout->remoteVersion >= 70300)
6138         {
6139                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
6140                                                          "castsource, casttarget, castfunc, castcontext, "
6141                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6142                                                          "FROM pg_cast ORDER BY 3,4");
6143         }
6144         else
6145         {
6146                 appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, "
6147                                                          "t1.oid AS castsource, t2.oid AS casttarget, "
6148                                                          "p.oid AS castfunc, 'e' AS castcontext, "
6149                                                          "'f' AS castmethod "
6150                                                          "FROM pg_type t1, pg_type t2, pg_proc p "
6151                                                          "WHERE p.pronargs = 1 AND "
6152                                                          "p.proargtypes[0] = t1.oid AND "
6153                                                          "p.prorettype = t2.oid AND p.proname = t2.typname "
6154                                                          "ORDER BY 3,4");
6155         }
6156
6157         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6158
6159         ntups = PQntuples(res);
6160
6161         *numCasts = ntups;
6162
6163         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6164
6165         i_tableoid = PQfnumber(res, "tableoid");
6166         i_oid = PQfnumber(res, "oid");
6167         i_castsource = PQfnumber(res, "castsource");
6168         i_casttarget = PQfnumber(res, "casttarget");
6169         i_castfunc = PQfnumber(res, "castfunc");
6170         i_castcontext = PQfnumber(res, "castcontext");
6171         i_castmethod = PQfnumber(res, "castmethod");
6172
6173         for (i = 0; i < ntups; i++)
6174         {
6175                 PQExpBufferData namebuf;
6176                 TypeInfo   *sTypeInfo;
6177                 TypeInfo   *tTypeInfo;
6178
6179                 castinfo[i].dobj.objType = DO_CAST;
6180                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6181                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6182                 AssignDumpId(&castinfo[i].dobj);
6183                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6184                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6185                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6186                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6187                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6188
6189                 /*
6190                  * Try to name cast as concatenation of typnames.  This is only used
6191                  * for purposes of sorting.  If we fail to find either type, the name
6192                  * will be an empty string.
6193                  */
6194                 initPQExpBuffer(&namebuf);
6195                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6196                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6197                 if (sTypeInfo && tTypeInfo)
6198                         appendPQExpBuffer(&namebuf, "%s %s",
6199                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6200                 castinfo[i].dobj.name = namebuf.data;
6201
6202                 if (OidIsValid(castinfo[i].castfunc))
6203                 {
6204                         /*
6205                          * We need to make a dependency to ensure the function will be
6206                          * dumped first.  (In 7.3 and later the regular dependency
6207                          * mechanism will handle this for us.)
6208                          */
6209                         FuncInfo   *funcInfo;
6210
6211                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6212                         if (funcInfo)
6213                                 addObjectDependency(&castinfo[i].dobj,
6214                                                                         funcInfo->dobj.dumpId);
6215                 }
6216         }
6217
6218         PQclear(res);
6219
6220         destroyPQExpBuffer(query);
6221
6222         return castinfo;
6223 }
6224
6225 /*
6226  * getTableAttrs -
6227  *        for each interesting table, read info about its attributes
6228  *        (names, types, default values, CHECK constraints, etc)
6229  *
6230  * This is implemented in a very inefficient way right now, looping
6231  * through the tblinfo and doing a join per table to find the attrs and their
6232  * types.  However, because we want type names and so forth to be named
6233  * relative to the schema of each table, we couldn't do it in just one
6234  * query.  (Maybe one query per schema?)
6235  *
6236  *      modifies tblinfo
6237  */
6238 void
6239 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
6240 {
6241         int                     i,
6242                                 j;
6243         PQExpBuffer q = createPQExpBuffer();
6244         int                     i_attnum;
6245         int                     i_attname;
6246         int                     i_atttypname;
6247         int                     i_atttypmod;
6248         int                     i_attstattarget;
6249         int                     i_attstorage;
6250         int                     i_typstorage;
6251         int                     i_attnotnull;
6252         int                     i_atthasdef;
6253         int                     i_attisdropped;
6254         int                     i_attlen;
6255         int                     i_attalign;
6256         int                     i_attislocal;
6257         int                     i_attoptions;
6258         int                     i_attcollation;
6259         int                     i_attfdwoptions;
6260         PGresult   *res;
6261         int                     ntups;
6262         bool            hasdefaults;
6263
6264         for (i = 0; i < numTables; i++)
6265         {
6266                 TableInfo  *tbinfo = &tblinfo[i];
6267
6268                 /* Don't bother to collect info for sequences */
6269                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6270                         continue;
6271
6272                 /* Don't bother with uninteresting tables, either */
6273                 if (!tbinfo->interesting)
6274                         continue;
6275
6276                 /*
6277                  * Make sure we are in proper schema for this table; this allows
6278                  * correct retrieval of formatted type names and default exprs
6279                  */
6280                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6281
6282                 /* find all the user attributes and their types */
6283
6284                 /*
6285                  * we must read the attribute names in attribute number order! because
6286                  * we will use the attnum to index into the attnames array later.  We
6287                  * actually ask to order by "attrelid, attnum" because (at least up to
6288                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6289                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6290                  */
6291                 if (g_verbose)
6292                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
6293                                           tbinfo->dobj.name);
6294
6295                 resetPQExpBuffer(q);
6296
6297                 if (fout->remoteVersion >= 90200)
6298                 {
6299                         /*
6300                          * attfdwoptions is new in 9.2.
6301                          */
6302                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6303                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6304                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6305                                                           "a.attlen, a.attalign, a.attislocal, "
6306                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6307                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6308                                                           "CASE WHEN a.attcollation <> t.typcollation "
6309                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6310                                                           "pg_catalog.array_to_string(ARRAY("
6311                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6312                                                           "' ' || pg_catalog.quote_literal(option_value) "
6313                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6314                                                           "ORDER BY option_name"
6315                                                           "), E',\n    ') AS attfdwoptions "
6316                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6317                                                           "ON a.atttypid = t.oid "
6318                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6319                                                           "AND a.attnum > 0::pg_catalog.int2 "
6320                                                           "ORDER BY a.attrelid, a.attnum",
6321                                                           tbinfo->dobj.catId.oid);
6322                 }
6323                 else if (fout->remoteVersion >= 90100)
6324                 {
6325                         /*
6326                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6327                          * clauses for attributes whose collation is different from their
6328                          * type's default, we use a CASE here to suppress uninteresting
6329                          * attcollations cheaply.
6330                          */
6331                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6332                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6333                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6334                                                           "a.attlen, a.attalign, a.attislocal, "
6335                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6336                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6337                                                           "CASE WHEN a.attcollation <> t.typcollation "
6338                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6339                                                           "NULL AS attfdwoptions "
6340                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6341                                                           "ON a.atttypid = t.oid "
6342                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6343                                                           "AND a.attnum > 0::pg_catalog.int2 "
6344                                                           "ORDER BY a.attrelid, a.attnum",
6345                                                           tbinfo->dobj.catId.oid);
6346                 }
6347                 else if (fout->remoteVersion >= 90000)
6348                 {
6349                         /* attoptions is new in 9.0 */
6350                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6351                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6352                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6353                                                           "a.attlen, a.attalign, a.attislocal, "
6354                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6355                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6356                                                           "0 AS attcollation, "
6357                                                           "NULL AS attfdwoptions "
6358                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6359                                                           "ON a.atttypid = t.oid "
6360                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6361                                                           "AND a.attnum > 0::pg_catalog.int2 "
6362                                                           "ORDER BY a.attrelid, a.attnum",
6363                                                           tbinfo->dobj.catId.oid);
6364                 }
6365                 else if (fout->remoteVersion >= 70300)
6366                 {
6367                         /* need left join here to not fail on dropped columns ... */
6368                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6369                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6370                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6371                                                           "a.attlen, a.attalign, a.attislocal, "
6372                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6373                                                           "'' AS attoptions, 0 AS attcollation, "
6374                                                           "NULL AS attfdwoptions "
6375                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6376                                                           "ON a.atttypid = t.oid "
6377                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6378                                                           "AND a.attnum > 0::pg_catalog.int2 "
6379                                                           "ORDER BY a.attrelid, a.attnum",
6380                                                           tbinfo->dobj.catId.oid);
6381                 }
6382                 else if (fout->remoteVersion >= 70100)
6383                 {
6384                         /*
6385                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6386                          * we don't dump it because we can't tell whether it's been
6387                          * explicitly set or was just a default.
6388                          *
6389                          * attislocal doesn't exist before 7.3, either; in older databases
6390                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6391                          */
6392                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6393                                                           "-1 AS attstattarget, a.attstorage, "
6394                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6395                                                           "false AS attisdropped, a.attlen, "
6396                                                           "a.attalign, true AS attislocal, "
6397                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6398                                                           "'' AS attoptions, 0 AS attcollation, "
6399                                                           "NULL AS attfdwoptions "
6400                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6401                                                           "ON a.atttypid = t.oid "
6402                                                           "WHERE a.attrelid = '%u'::oid "
6403                                                           "AND a.attnum > 0::int2 "
6404                                                           "ORDER BY a.attrelid, a.attnum",
6405                                                           tbinfo->dobj.catId.oid);
6406                 }
6407                 else
6408                 {
6409                         /* format_type not available before 7.1 */
6410                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6411                                                           "-1 AS attstattarget, "
6412                                                           "attstorage, attstorage AS typstorage, "
6413                                                           "attnotnull, atthasdef, false AS attisdropped, "
6414                                                           "attlen, attalign, "
6415                                                           "true AS attislocal, "
6416                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6417                                                           "'' AS attoptions, 0 AS attcollation, "
6418                                                           "NULL AS attfdwoptions "
6419                                                           "FROM pg_attribute a "
6420                                                           "WHERE attrelid = '%u'::oid "
6421                                                           "AND attnum > 0::int2 "
6422                                                           "ORDER BY attrelid, attnum",
6423                                                           tbinfo->dobj.catId.oid);
6424                 }
6425
6426                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6427
6428                 ntups = PQntuples(res);
6429
6430                 i_attnum = PQfnumber(res, "attnum");
6431                 i_attname = PQfnumber(res, "attname");
6432                 i_atttypname = PQfnumber(res, "atttypname");
6433                 i_atttypmod = PQfnumber(res, "atttypmod");
6434                 i_attstattarget = PQfnumber(res, "attstattarget");
6435                 i_attstorage = PQfnumber(res, "attstorage");
6436                 i_typstorage = PQfnumber(res, "typstorage");
6437                 i_attnotnull = PQfnumber(res, "attnotnull");
6438                 i_atthasdef = PQfnumber(res, "atthasdef");
6439                 i_attisdropped = PQfnumber(res, "attisdropped");
6440                 i_attlen = PQfnumber(res, "attlen");
6441                 i_attalign = PQfnumber(res, "attalign");
6442                 i_attislocal = PQfnumber(res, "attislocal");
6443                 i_attoptions = PQfnumber(res, "attoptions");
6444                 i_attcollation = PQfnumber(res, "attcollation");
6445                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6446
6447                 tbinfo->numatts = ntups;
6448                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6449                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6450                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6451                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6452                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6453                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6454                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6455                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6456                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6457                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6458                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6459                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6460                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6461                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6462                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6463                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6464                 hasdefaults = false;
6465
6466                 for (j = 0; j < ntups; j++)
6467                 {
6468                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6469                                 exit_horribly(NULL,
6470                                                           "invalid column numbering in table \"%s\"\n",
6471                                                           tbinfo->dobj.name);
6472                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6473                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6474                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6475                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6476                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6477                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6478                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6479                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6480                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6481                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6482                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6483                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6484                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6485                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6486                         tbinfo->attrdefs[j] = NULL; /* fix below */
6487                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6488                                 hasdefaults = true;
6489                         /* these flags will be set in flagInhAttrs() */
6490                         tbinfo->inhNotNull[j] = false;
6491                 }
6492
6493                 PQclear(res);
6494
6495                 /*
6496                  * Get info about column defaults
6497                  */
6498                 if (hasdefaults)
6499                 {
6500                         AttrDefInfo *attrdefs;
6501                         int                     numDefaults;
6502
6503                         if (g_verbose)
6504                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
6505                                                   tbinfo->dobj.name);
6506
6507                         resetPQExpBuffer(q);
6508                         if (fout->remoteVersion >= 70300)
6509                         {
6510                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6511                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6512                                                                   "FROM pg_catalog.pg_attrdef "
6513                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6514                                                                   tbinfo->dobj.catId.oid);
6515                         }
6516                         else if (fout->remoteVersion >= 70200)
6517                         {
6518                                 /* 7.2 did not have OIDs in pg_attrdef */
6519                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6520                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6521                                                                   "FROM pg_attrdef "
6522                                                                   "WHERE adrelid = '%u'::oid",
6523                                                                   tbinfo->dobj.catId.oid);
6524                         }
6525                         else if (fout->remoteVersion >= 70100)
6526                         {
6527                                 /* no pg_get_expr, so must rely on adsrc */
6528                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6529                                                                   "FROM pg_attrdef "
6530                                                                   "WHERE adrelid = '%u'::oid",
6531                                                                   tbinfo->dobj.catId.oid);
6532                         }
6533                         else
6534                         {
6535                                 /* no pg_get_expr, no tableoid either */
6536                                 appendPQExpBuffer(q, "SELECT "
6537                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6538                                                                   "oid, adnum, adsrc "
6539                                                                   "FROM pg_attrdef "
6540                                                                   "WHERE adrelid = '%u'::oid",
6541                                                                   tbinfo->dobj.catId.oid);
6542                         }
6543                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6544
6545                         numDefaults = PQntuples(res);
6546                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6547
6548                         for (j = 0; j < numDefaults; j++)
6549                         {
6550                                 int                     adnum;
6551
6552                                 adnum = atoi(PQgetvalue(res, j, 2));
6553
6554                                 if (adnum <= 0 || adnum > ntups)
6555                                         exit_horribly(NULL,
6556                                                                   "invalid adnum value %d for table \"%s\"\n",
6557                                                                   adnum, tbinfo->dobj.name);
6558
6559                                 /*
6560                                  * dropped columns shouldn't have defaults, but just in case,
6561                                  * ignore 'em
6562                                  */
6563                                 if (tbinfo->attisdropped[adnum - 1])
6564                                         continue;
6565
6566                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6567                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6568                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6569                                 AssignDumpId(&attrdefs[j].dobj);
6570                                 attrdefs[j].adtable = tbinfo;
6571                                 attrdefs[j].adnum = adnum;
6572                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6573
6574                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6575                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6576
6577                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6578
6579                                 /*
6580                                  * Defaults on a VIEW must always be dumped as separate ALTER
6581                                  * TABLE commands.      Defaults on regular tables are dumped as
6582                                  * part of the CREATE TABLE if possible, which it won't be if
6583                                  * the column is not going to be emitted explicitly.
6584                                  */
6585                                 if (tbinfo->relkind == RELKIND_VIEW)
6586                                 {
6587                                         attrdefs[j].separate = true;
6588                                         /* needed in case pre-7.3 DB: */
6589                                         addObjectDependency(&attrdefs[j].dobj,
6590                                                                                 tbinfo->dobj.dumpId);
6591                                 }
6592                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6593                                 {
6594                                         /* column will be suppressed, print default separately */
6595                                         attrdefs[j].separate = true;
6596                                         /* needed in case pre-7.3 DB: */
6597                                         addObjectDependency(&attrdefs[j].dobj,
6598                                                                                 tbinfo->dobj.dumpId);
6599                                 }
6600                                 else
6601                                 {
6602                                         attrdefs[j].separate = false;
6603
6604                                         /*
6605                                          * Mark the default as needing to appear before the table,
6606                                          * so that any dependencies it has must be emitted before
6607                                          * the CREATE TABLE.  If this is not possible, we'll
6608                                          * change to "separate" mode while sorting dependencies.
6609                                          */
6610                                         addObjectDependency(&tbinfo->dobj,
6611                                                                                 attrdefs[j].dobj.dumpId);
6612                                 }
6613
6614                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6615                         }
6616                         PQclear(res);
6617                 }
6618
6619                 /*
6620                  * Get info about table CHECK constraints
6621                  */
6622                 if (tbinfo->ncheck > 0)
6623                 {
6624                         ConstraintInfo *constrs;
6625                         int                     numConstrs;
6626
6627                         if (g_verbose)
6628                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6629                                                   tbinfo->dobj.name);
6630
6631                         resetPQExpBuffer(q);
6632                         if (fout->remoteVersion >= 90200)
6633                         {
6634                                 /*
6635                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6636                                  * but it wasn't ever false for check constraints until 9.2).
6637                                  */
6638                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6639                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6640                                                                   "conislocal, convalidated "
6641                                                                   "FROM pg_catalog.pg_constraint "
6642                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6643                                                                   "   AND contype = 'c' "
6644                                                                   "ORDER BY conname",
6645                                                                   tbinfo->dobj.catId.oid);
6646                         }
6647                         else if (fout->remoteVersion >= 80400)
6648                         {
6649                                 /* conislocal is new in 8.4 */
6650                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6651                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6652                                                                   "conislocal, true AS convalidated "
6653                                                                   "FROM pg_catalog.pg_constraint "
6654                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6655                                                                   "   AND contype = 'c' "
6656                                                                   "ORDER BY conname",
6657                                                                   tbinfo->dobj.catId.oid);
6658                         }
6659                         else if (fout->remoteVersion >= 70400)
6660                         {
6661                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6662                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6663                                                                   "true AS conislocal, true AS convalidated "
6664                                                                   "FROM pg_catalog.pg_constraint "
6665                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6666                                                                   "   AND contype = 'c' "
6667                                                                   "ORDER BY conname",
6668                                                                   tbinfo->dobj.catId.oid);
6669                         }
6670                         else if (fout->remoteVersion >= 70300)
6671                         {
6672                                 /* no pg_get_constraintdef, must use consrc */
6673                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6674                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6675                                                                   "true AS conislocal, true AS convalidated "
6676                                                                   "FROM pg_catalog.pg_constraint "
6677                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6678                                                                   "   AND contype = 'c' "
6679                                                                   "ORDER BY conname",
6680                                                                   tbinfo->dobj.catId.oid);
6681                         }
6682                         else if (fout->remoteVersion >= 70200)
6683                         {
6684                                 /* 7.2 did not have OIDs in pg_relcheck */
6685                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6686                                                                   "rcname AS conname, "
6687                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6688                                                                   "true AS conislocal, true AS convalidated "
6689                                                                   "FROM pg_relcheck "
6690                                                                   "WHERE rcrelid = '%u'::oid "
6691                                                                   "ORDER BY rcname",
6692                                                                   tbinfo->dobj.catId.oid);
6693                         }
6694                         else if (fout->remoteVersion >= 70100)
6695                         {
6696                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6697                                                                   "rcname AS conname, "
6698                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6699                                                                   "true AS conislocal, true AS convalidated "
6700                                                                   "FROM pg_relcheck "
6701                                                                   "WHERE rcrelid = '%u'::oid "
6702                                                                   "ORDER BY rcname",
6703                                                                   tbinfo->dobj.catId.oid);
6704                         }
6705                         else
6706                         {
6707                                 /* no tableoid in 7.0 */
6708                                 appendPQExpBuffer(q, "SELECT "
6709                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6710                                                                   "oid, rcname AS conname, "
6711                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6712                                                                   "true AS conislocal, true AS convalidated "
6713                                                                   "FROM pg_relcheck "
6714                                                                   "WHERE rcrelid = '%u'::oid "
6715                                                                   "ORDER BY rcname",
6716                                                                   tbinfo->dobj.catId.oid);
6717                         }
6718                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6719
6720                         numConstrs = PQntuples(res);
6721                         if (numConstrs != tbinfo->ncheck)
6722                         {
6723                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6724                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6725                                                                                  tbinfo->ncheck),
6726                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6727                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6728                                 exit_nicely(1);
6729                         }
6730
6731                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6732                         tbinfo->checkexprs = constrs;
6733
6734                         for (j = 0; j < numConstrs; j++)
6735                         {
6736                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6737
6738                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6739                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6740                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6741                                 AssignDumpId(&constrs[j].dobj);
6742                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6743                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6744                                 constrs[j].contable = tbinfo;
6745                                 constrs[j].condomain = NULL;
6746                                 constrs[j].contype = 'c';
6747                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6748                                 constrs[j].confrelid = InvalidOid;
6749                                 constrs[j].conindex = 0;
6750                                 constrs[j].condeferrable = false;
6751                                 constrs[j].condeferred = false;
6752                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6753
6754                                 /*
6755                                  * An unvalidated constraint needs to be dumped separately, so
6756                                  * that potentially-violating existing data is loaded before
6757                                  * the constraint.
6758                                  */
6759                                 constrs[j].separate = !validated;
6760
6761                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6762
6763                                 /*
6764                                  * Mark the constraint as needing to appear before the table
6765                                  * --- this is so that any other dependencies of the
6766                                  * constraint will be emitted before we try to create the
6767                                  * table.  If the constraint is to be dumped separately, it
6768                                  * will be dumped after data is loaded anyway, so don't do it.
6769                                  * (There's an automatic dependency in the opposite direction
6770                                  * anyway, so don't need to add one manually here.)
6771                                  */
6772                                 if (!constrs[j].separate)
6773                                         addObjectDependency(&tbinfo->dobj,
6774                                                                                 constrs[j].dobj.dumpId);
6775
6776                                 /*
6777                                  * If the constraint is inherited, this will be detected later
6778                                  * (in pre-8.4 databases).      We also detect later if the
6779                                  * constraint must be split out from the table definition.
6780                                  */
6781                         }
6782                         PQclear(res);
6783                 }
6784         }
6785
6786         destroyPQExpBuffer(q);
6787 }
6788
6789 /*
6790  * Test whether a column should be printed as part of table's CREATE TABLE.
6791  * Column number is zero-based.
6792  *
6793  * Normally this is always true, but it's false for dropped columns, as well
6794  * as those that were inherited without any local definition.  (If we print
6795  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6796  * However, in binary_upgrade mode, we must print all such columns anyway and
6797  * fix the attislocal/attisdropped state later, so as to keep control of the
6798  * physical column order.
6799  *
6800  * This function exists because there are scattered nonobvious places that
6801  * must be kept in sync with this decision.
6802  */
6803 bool
6804 shouldPrintColumn(TableInfo *tbinfo, int colno)
6805 {
6806         if (binary_upgrade)
6807                 return true;
6808         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6809 }
6810
6811
6812 /*
6813  * getTSParsers:
6814  *        read all text search parsers in the system catalogs and return them
6815  *        in the TSParserInfo* structure
6816  *
6817  *      numTSParsers is set to the number of parsers read in
6818  */
6819 TSParserInfo *
6820 getTSParsers(Archive *fout, int *numTSParsers)
6821 {
6822         PGresult   *res;
6823         int                     ntups;
6824         int                     i;
6825         PQExpBuffer query;
6826         TSParserInfo *prsinfo;
6827         int                     i_tableoid;
6828         int                     i_oid;
6829         int                     i_prsname;
6830         int                     i_prsnamespace;
6831         int                     i_prsstart;
6832         int                     i_prstoken;
6833         int                     i_prsend;
6834         int                     i_prsheadline;
6835         int                     i_prslextype;
6836
6837         /* Before 8.3, there is no built-in text search support */
6838         if (fout->remoteVersion < 80300)
6839         {
6840                 *numTSParsers = 0;
6841                 return NULL;
6842         }
6843
6844         query = createPQExpBuffer();
6845
6846         /*
6847          * find all text search objects, including builtin ones; we filter out
6848          * system-defined objects at dump-out time.
6849          */
6850
6851         /* Make sure we are in proper schema */
6852         selectSourceSchema(fout, "pg_catalog");
6853
6854         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6855                                                  "prsstart::oid, prstoken::oid, "
6856                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
6857                                                  "FROM pg_ts_parser");
6858
6859         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6860
6861         ntups = PQntuples(res);
6862         *numTSParsers = ntups;
6863
6864         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6865
6866         i_tableoid = PQfnumber(res, "tableoid");
6867         i_oid = PQfnumber(res, "oid");
6868         i_prsname = PQfnumber(res, "prsname");
6869         i_prsnamespace = PQfnumber(res, "prsnamespace");
6870         i_prsstart = PQfnumber(res, "prsstart");
6871         i_prstoken = PQfnumber(res, "prstoken");
6872         i_prsend = PQfnumber(res, "prsend");
6873         i_prsheadline = PQfnumber(res, "prsheadline");
6874         i_prslextype = PQfnumber(res, "prslextype");
6875
6876         for (i = 0; i < ntups; i++)
6877         {
6878                 prsinfo[i].dobj.objType = DO_TSPARSER;
6879                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6880                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6881                 AssignDumpId(&prsinfo[i].dobj);
6882                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6883                 prsinfo[i].dobj.namespace =
6884                         findNamespace(fout,
6885                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6886                                                   prsinfo[i].dobj.catId.oid);
6887                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6888                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6889                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6890                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6891                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6892
6893                 /* Decide whether we want to dump it */
6894                 selectDumpableObject(&(prsinfo[i].dobj));
6895         }
6896
6897         PQclear(res);
6898
6899         destroyPQExpBuffer(query);
6900
6901         return prsinfo;
6902 }
6903
6904 /*
6905  * getTSDictionaries:
6906  *        read all text search dictionaries in the system catalogs and return them
6907  *        in the TSDictInfo* structure
6908  *
6909  *      numTSDicts is set to the number of dictionaries read in
6910  */
6911 TSDictInfo *
6912 getTSDictionaries(Archive *fout, int *numTSDicts)
6913 {
6914         PGresult   *res;
6915         int                     ntups;
6916         int                     i;
6917         PQExpBuffer query;
6918         TSDictInfo *dictinfo;
6919         int                     i_tableoid;
6920         int                     i_oid;
6921         int                     i_dictname;
6922         int                     i_dictnamespace;
6923         int                     i_rolname;
6924         int                     i_dicttemplate;
6925         int                     i_dictinitoption;
6926
6927         /* Before 8.3, there is no built-in text search support */
6928         if (fout->remoteVersion < 80300)
6929         {
6930                 *numTSDicts = 0;
6931                 return NULL;
6932         }
6933
6934         query = createPQExpBuffer();
6935
6936         /* Make sure we are in proper schema */
6937         selectSourceSchema(fout, "pg_catalog");
6938
6939         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6940                                           "dictnamespace, (%s dictowner) AS rolname, "
6941                                           "dicttemplate, dictinitoption "
6942                                           "FROM pg_ts_dict",
6943                                           username_subquery);
6944
6945         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6946
6947         ntups = PQntuples(res);
6948         *numTSDicts = ntups;
6949
6950         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6951
6952         i_tableoid = PQfnumber(res, "tableoid");
6953         i_oid = PQfnumber(res, "oid");
6954         i_dictname = PQfnumber(res, "dictname");
6955         i_dictnamespace = PQfnumber(res, "dictnamespace");
6956         i_rolname = PQfnumber(res, "rolname");
6957         i_dictinitoption = PQfnumber(res, "dictinitoption");
6958         i_dicttemplate = PQfnumber(res, "dicttemplate");
6959
6960         for (i = 0; i < ntups; i++)
6961         {
6962                 dictinfo[i].dobj.objType = DO_TSDICT;
6963                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6964                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6965                 AssignDumpId(&dictinfo[i].dobj);
6966                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6967                 dictinfo[i].dobj.namespace =
6968                         findNamespace(fout,
6969                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6970                                                   dictinfo[i].dobj.catId.oid);
6971                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6972                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6973                 if (PQgetisnull(res, i, i_dictinitoption))
6974                         dictinfo[i].dictinitoption = NULL;
6975                 else
6976                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6977
6978                 /* Decide whether we want to dump it */
6979                 selectDumpableObject(&(dictinfo[i].dobj));
6980         }
6981
6982         PQclear(res);
6983
6984         destroyPQExpBuffer(query);
6985
6986         return dictinfo;
6987 }
6988
6989 /*
6990  * getTSTemplates:
6991  *        read all text search templates in the system catalogs and return them
6992  *        in the TSTemplateInfo* structure
6993  *
6994  *      numTSTemplates is set to the number of templates read in
6995  */
6996 TSTemplateInfo *
6997 getTSTemplates(Archive *fout, int *numTSTemplates)
6998 {
6999         PGresult   *res;
7000         int                     ntups;
7001         int                     i;
7002         PQExpBuffer query;
7003         TSTemplateInfo *tmplinfo;
7004         int                     i_tableoid;
7005         int                     i_oid;
7006         int                     i_tmplname;
7007         int                     i_tmplnamespace;
7008         int                     i_tmplinit;
7009         int                     i_tmpllexize;
7010
7011         /* Before 8.3, there is no built-in text search support */
7012         if (fout->remoteVersion < 80300)
7013         {
7014                 *numTSTemplates = 0;
7015                 return NULL;
7016         }
7017
7018         query = createPQExpBuffer();
7019
7020         /* Make sure we are in proper schema */
7021         selectSourceSchema(fout, "pg_catalog");
7022
7023         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
7024                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
7025                                                  "FROM pg_ts_template");
7026
7027         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7028
7029         ntups = PQntuples(res);
7030         *numTSTemplates = ntups;
7031
7032         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
7033
7034         i_tableoid = PQfnumber(res, "tableoid");
7035         i_oid = PQfnumber(res, "oid");
7036         i_tmplname = PQfnumber(res, "tmplname");
7037         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
7038         i_tmplinit = PQfnumber(res, "tmplinit");
7039         i_tmpllexize = PQfnumber(res, "tmpllexize");
7040
7041         for (i = 0; i < ntups; i++)
7042         {
7043                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
7044                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7045                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7046                 AssignDumpId(&tmplinfo[i].dobj);
7047                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
7048                 tmplinfo[i].dobj.namespace =
7049                         findNamespace(fout,
7050                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
7051                                                   tmplinfo[i].dobj.catId.oid);
7052                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
7053                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
7054
7055                 /* Decide whether we want to dump it */
7056                 selectDumpableObject(&(tmplinfo[i].dobj));
7057         }
7058
7059         PQclear(res);
7060
7061         destroyPQExpBuffer(query);
7062
7063         return tmplinfo;
7064 }
7065
7066 /*
7067  * getTSConfigurations:
7068  *        read all text search configurations in the system catalogs and return
7069  *        them in the TSConfigInfo* structure
7070  *
7071  *      numTSConfigs is set to the number of configurations read in
7072  */
7073 TSConfigInfo *
7074 getTSConfigurations(Archive *fout, int *numTSConfigs)
7075 {
7076         PGresult   *res;
7077         int                     ntups;
7078         int                     i;
7079         PQExpBuffer query;
7080         TSConfigInfo *cfginfo;
7081         int                     i_tableoid;
7082         int                     i_oid;
7083         int                     i_cfgname;
7084         int                     i_cfgnamespace;
7085         int                     i_rolname;
7086         int                     i_cfgparser;
7087
7088         /* Before 8.3, there is no built-in text search support */
7089         if (fout->remoteVersion < 80300)
7090         {
7091                 *numTSConfigs = 0;
7092                 return NULL;
7093         }
7094
7095         query = createPQExpBuffer();
7096
7097         /* Make sure we are in proper schema */
7098         selectSourceSchema(fout, "pg_catalog");
7099
7100         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
7101                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
7102                                           "FROM pg_ts_config",
7103                                           username_subquery);
7104
7105         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7106
7107         ntups = PQntuples(res);
7108         *numTSConfigs = ntups;
7109
7110         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
7111
7112         i_tableoid = PQfnumber(res, "tableoid");
7113         i_oid = PQfnumber(res, "oid");
7114         i_cfgname = PQfnumber(res, "cfgname");
7115         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
7116         i_rolname = PQfnumber(res, "rolname");
7117         i_cfgparser = PQfnumber(res, "cfgparser");
7118
7119         for (i = 0; i < ntups; i++)
7120         {
7121                 cfginfo[i].dobj.objType = DO_TSCONFIG;
7122                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7123                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7124                 AssignDumpId(&cfginfo[i].dobj);
7125                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
7126                 cfginfo[i].dobj.namespace =
7127                         findNamespace(fout,
7128                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
7129                                                   cfginfo[i].dobj.catId.oid);
7130                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7131                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7132
7133                 /* Decide whether we want to dump it */
7134                 selectDumpableObject(&(cfginfo[i].dobj));
7135         }
7136
7137         PQclear(res);
7138
7139         destroyPQExpBuffer(query);
7140
7141         return cfginfo;
7142 }
7143
7144 /*
7145  * getForeignDataWrappers:
7146  *        read all foreign-data wrappers in the system catalogs and return
7147  *        them in the FdwInfo* structure
7148  *
7149  *      numForeignDataWrappers is set to the number of fdws read in
7150  */
7151 FdwInfo *
7152 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7153 {
7154         PGresult   *res;
7155         int                     ntups;
7156         int                     i;
7157         PQExpBuffer query;
7158         FdwInfo    *fdwinfo;
7159         int                     i_tableoid;
7160         int                     i_oid;
7161         int                     i_fdwname;
7162         int                     i_rolname;
7163         int                     i_fdwhandler;
7164         int                     i_fdwvalidator;
7165         int                     i_fdwacl;
7166         int                     i_fdwoptions;
7167
7168         /* Before 8.4, there are no foreign-data wrappers */
7169         if (fout->remoteVersion < 80400)
7170         {
7171                 *numForeignDataWrappers = 0;
7172                 return NULL;
7173         }
7174
7175         query = createPQExpBuffer();
7176
7177         /* Make sure we are in proper schema */
7178         selectSourceSchema(fout, "pg_catalog");
7179
7180         if (fout->remoteVersion >= 90100)
7181         {
7182                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7183                                                   "(%s fdwowner) AS rolname, "
7184                                                   "fdwhandler::pg_catalog.regproc, "
7185                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7186                                                   "array_to_string(ARRAY("
7187                                                   "SELECT quote_ident(option_name) || ' ' || "
7188                                                   "quote_literal(option_value) "
7189                                                   "FROM pg_options_to_table(fdwoptions) "
7190                                                   "ORDER BY option_name"
7191                                                   "), E',\n    ') AS fdwoptions "
7192                                                   "FROM pg_foreign_data_wrapper",
7193                                                   username_subquery);
7194         }
7195         else
7196         {
7197                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7198                                                   "(%s fdwowner) AS rolname, "
7199                                                   "'-' AS fdwhandler, "
7200                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7201                                                   "array_to_string(ARRAY("
7202                                                   "SELECT quote_ident(option_name) || ' ' || "
7203                                                   "quote_literal(option_value) "
7204                                                   "FROM pg_options_to_table(fdwoptions) "
7205                                                   "ORDER BY option_name"
7206                                                   "), E',\n    ') AS fdwoptions "
7207                                                   "FROM pg_foreign_data_wrapper",
7208                                                   username_subquery);
7209         }
7210
7211         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7212
7213         ntups = PQntuples(res);
7214         *numForeignDataWrappers = ntups;
7215
7216         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7217
7218         i_tableoid = PQfnumber(res, "tableoid");
7219         i_oid = PQfnumber(res, "oid");
7220         i_fdwname = PQfnumber(res, "fdwname");
7221         i_rolname = PQfnumber(res, "rolname");
7222         i_fdwhandler = PQfnumber(res, "fdwhandler");
7223         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7224         i_fdwacl = PQfnumber(res, "fdwacl");
7225         i_fdwoptions = PQfnumber(res, "fdwoptions");
7226
7227         for (i = 0; i < ntups; i++)
7228         {
7229                 fdwinfo[i].dobj.objType = DO_FDW;
7230                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7231                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7232                 AssignDumpId(&fdwinfo[i].dobj);
7233                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7234                 fdwinfo[i].dobj.namespace = NULL;
7235                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7236                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7237                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7238                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7239                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7240
7241                 /* Decide whether we want to dump it */
7242                 selectDumpableObject(&(fdwinfo[i].dobj));
7243         }
7244
7245         PQclear(res);
7246
7247         destroyPQExpBuffer(query);
7248
7249         return fdwinfo;
7250 }
7251
7252 /*
7253  * getForeignServers:
7254  *        read all foreign servers in the system catalogs and return
7255  *        them in the ForeignServerInfo * structure
7256  *
7257  *      numForeignServers is set to the number of servers read in
7258  */
7259 ForeignServerInfo *
7260 getForeignServers(Archive *fout, int *numForeignServers)
7261 {
7262         PGresult   *res;
7263         int                     ntups;
7264         int                     i;
7265         PQExpBuffer query;
7266         ForeignServerInfo *srvinfo;
7267         int                     i_tableoid;
7268         int                     i_oid;
7269         int                     i_srvname;
7270         int                     i_rolname;
7271         int                     i_srvfdw;
7272         int                     i_srvtype;
7273         int                     i_srvversion;
7274         int                     i_srvacl;
7275         int                     i_srvoptions;
7276
7277         /* Before 8.4, there are no foreign servers */
7278         if (fout->remoteVersion < 80400)
7279         {
7280                 *numForeignServers = 0;
7281                 return NULL;
7282         }
7283
7284         query = createPQExpBuffer();
7285
7286         /* Make sure we are in proper schema */
7287         selectSourceSchema(fout, "pg_catalog");
7288
7289         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7290                                           "(%s srvowner) AS rolname, "
7291                                           "srvfdw, srvtype, srvversion, srvacl,"
7292                                           "array_to_string(ARRAY("
7293                                           "SELECT quote_ident(option_name) || ' ' || "
7294                                           "quote_literal(option_value) "
7295                                           "FROM pg_options_to_table(srvoptions) "
7296                                           "ORDER BY option_name"
7297                                           "), E',\n    ') AS srvoptions "
7298                                           "FROM pg_foreign_server",
7299                                           username_subquery);
7300
7301         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7302
7303         ntups = PQntuples(res);
7304         *numForeignServers = ntups;
7305
7306         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7307
7308         i_tableoid = PQfnumber(res, "tableoid");
7309         i_oid = PQfnumber(res, "oid");
7310         i_srvname = PQfnumber(res, "srvname");
7311         i_rolname = PQfnumber(res, "rolname");
7312         i_srvfdw = PQfnumber(res, "srvfdw");
7313         i_srvtype = PQfnumber(res, "srvtype");
7314         i_srvversion = PQfnumber(res, "srvversion");
7315         i_srvacl = PQfnumber(res, "srvacl");
7316         i_srvoptions = PQfnumber(res, "srvoptions");
7317
7318         for (i = 0; i < ntups; i++)
7319         {
7320                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7321                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7322                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7323                 AssignDumpId(&srvinfo[i].dobj);
7324                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7325                 srvinfo[i].dobj.namespace = NULL;
7326                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7327                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7328                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7329                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7330                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7331                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7332
7333                 /* Decide whether we want to dump it */
7334                 selectDumpableObject(&(srvinfo[i].dobj));
7335         }
7336
7337         PQclear(res);
7338
7339         destroyPQExpBuffer(query);
7340
7341         return srvinfo;
7342 }
7343
7344 /*
7345  * getDefaultACLs:
7346  *        read all default ACL information in the system catalogs and return
7347  *        them in the DefaultACLInfo structure
7348  *
7349  *      numDefaultACLs is set to the number of ACLs read in
7350  */
7351 DefaultACLInfo *
7352 getDefaultACLs(Archive *fout, int *numDefaultACLs)
7353 {
7354         DefaultACLInfo *daclinfo;
7355         PQExpBuffer query;
7356         PGresult   *res;
7357         int                     i_oid;
7358         int                     i_tableoid;
7359         int                     i_defaclrole;
7360         int                     i_defaclnamespace;
7361         int                     i_defaclobjtype;
7362         int                     i_defaclacl;
7363         int                     i,
7364                                 ntups;
7365
7366         if (fout->remoteVersion < 90000)
7367         {
7368                 *numDefaultACLs = 0;
7369                 return NULL;
7370         }
7371
7372         query = createPQExpBuffer();
7373
7374         /* Make sure we are in proper schema */
7375         selectSourceSchema(fout, "pg_catalog");
7376
7377         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7378                                           "(%s defaclrole) AS defaclrole, "
7379                                           "defaclnamespace, "
7380                                           "defaclobjtype, "
7381                                           "defaclacl "
7382                                           "FROM pg_default_acl",
7383                                           username_subquery);
7384
7385         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7386
7387         ntups = PQntuples(res);
7388         *numDefaultACLs = ntups;
7389
7390         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7391
7392         i_oid = PQfnumber(res, "oid");
7393         i_tableoid = PQfnumber(res, "tableoid");
7394         i_defaclrole = PQfnumber(res, "defaclrole");
7395         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7396         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7397         i_defaclacl = PQfnumber(res, "defaclacl");
7398
7399         for (i = 0; i < ntups; i++)
7400         {
7401                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7402
7403                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7404                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7405                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7406                 AssignDumpId(&daclinfo[i].dobj);
7407                 /* cheesy ... is it worth coming up with a better object name? */
7408                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7409
7410                 if (nspid != InvalidOid)
7411                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7412                                                                                                  daclinfo[i].dobj.catId.oid);
7413                 else
7414                         daclinfo[i].dobj.namespace = NULL;
7415
7416                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7417                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7418                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7419
7420                 /* Decide whether we want to dump it */
7421                 selectDumpableDefaultACL(&(daclinfo[i]));
7422         }
7423
7424         PQclear(res);
7425
7426         destroyPQExpBuffer(query);
7427
7428         return daclinfo;
7429 }
7430
7431 /*
7432  * dumpComment --
7433  *
7434  * This routine is used to dump any comments associated with the
7435  * object handed to this routine. The routine takes a constant character
7436  * string for the target part of the comment-creation command, plus
7437  * the namespace and owner of the object (for labeling the ArchiveEntry),
7438  * plus catalog ID and subid which are the lookup key for pg_description,
7439  * plus the dump ID for the object (for setting a dependency).
7440  * If a matching pg_description entry is found, it is dumped.
7441  *
7442  * Note: although this routine takes a dumpId for dependency purposes,
7443  * that purpose is just to mark the dependency in the emitted dump file
7444  * for possible future use by pg_restore.  We do NOT use it for determining
7445  * ordering of the comment in the dump file, because this routine is called
7446  * after dependency sorting occurs.  This routine should be called just after
7447  * calling ArchiveEntry() for the specified object.
7448  */
7449 static void
7450 dumpComment(Archive *fout, const char *target,
7451                         const char *namespace, const char *owner,
7452                         CatalogId catalogId, int subid, DumpId dumpId)
7453 {
7454         CommentItem *comments;
7455         int                     ncomments;
7456
7457         /* Comments are schema not data ... except blob comments are data */
7458         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7459         {
7460                 if (dataOnly)
7461                         return;
7462         }
7463         else
7464         {
7465                 if (schemaOnly)
7466                         return;
7467         }
7468
7469         /* Search for comments associated with catalogId, using table */
7470         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7471                                                          &comments);
7472
7473         /* Is there one matching the subid? */
7474         while (ncomments > 0)
7475         {
7476                 if (comments->objsubid == subid)
7477                         break;
7478                 comments++;
7479                 ncomments--;
7480         }
7481
7482         /* If a comment exists, build COMMENT ON statement */
7483         if (ncomments > 0)
7484         {
7485                 PQExpBuffer query = createPQExpBuffer();
7486
7487                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7488                 appendStringLiteralAH(query, comments->descr, fout);
7489                 appendPQExpBufferStr(query, ";\n");
7490
7491                 /*
7492                  * We mark comments as SECTION_NONE because they really belong in the
7493                  * same section as their parent, whether that is pre-data or
7494                  * post-data.
7495                  */
7496                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7497                                          target, namespace, NULL, owner,
7498                                          false, "COMMENT", SECTION_NONE,
7499                                          query->data, "", NULL,
7500                                          &(dumpId), 1,
7501                                          NULL, NULL);
7502
7503                 destroyPQExpBuffer(query);
7504         }
7505 }
7506
7507 /*
7508  * dumpTableComment --
7509  *
7510  * As above, but dump comments for both the specified table (or view)
7511  * and its columns.
7512  */
7513 static void
7514 dumpTableComment(Archive *fout, TableInfo *tbinfo,
7515                                  const char *reltypename)
7516 {
7517         CommentItem *comments;
7518         int                     ncomments;
7519         PQExpBuffer query;
7520         PQExpBuffer target;
7521
7522         /* Comments are SCHEMA not data */
7523         if (dataOnly)
7524                 return;
7525
7526         /* Search for comments associated with relation, using table */
7527         ncomments = findComments(fout,
7528                                                          tbinfo->dobj.catId.tableoid,
7529                                                          tbinfo->dobj.catId.oid,
7530                                                          &comments);
7531
7532         /* If comments exist, build COMMENT ON statements */
7533         if (ncomments <= 0)
7534                 return;
7535
7536         query = createPQExpBuffer();
7537         target = createPQExpBuffer();
7538
7539         while (ncomments > 0)
7540         {
7541                 const char *descr = comments->descr;
7542                 int                     objsubid = comments->objsubid;
7543
7544                 if (objsubid == 0)
7545                 {
7546                         resetPQExpBuffer(target);
7547                         appendPQExpBuffer(target, "%s %s", reltypename,
7548                                                           fmtId(tbinfo->dobj.name));
7549
7550                         resetPQExpBuffer(query);
7551                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7552                         appendStringLiteralAH(query, descr, fout);
7553                         appendPQExpBufferStr(query, ";\n");
7554
7555                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7556                                                  target->data,
7557                                                  tbinfo->dobj.namespace->dobj.name,
7558                                                  NULL, tbinfo->rolname,
7559                                                  false, "COMMENT", SECTION_NONE,
7560                                                  query->data, "", NULL,
7561                                                  &(tbinfo->dobj.dumpId), 1,
7562                                                  NULL, NULL);
7563                 }
7564                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7565                 {
7566                         resetPQExpBuffer(target);
7567                         appendPQExpBuffer(target, "COLUMN %s.",
7568                                                           fmtId(tbinfo->dobj.name));
7569                         appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1]));
7570
7571                         resetPQExpBuffer(query);
7572                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7573                         appendStringLiteralAH(query, descr, fout);
7574                         appendPQExpBufferStr(query, ";\n");
7575
7576                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7577                                                  target->data,
7578                                                  tbinfo->dobj.namespace->dobj.name,
7579                                                  NULL, tbinfo->rolname,
7580                                                  false, "COMMENT", SECTION_NONE,
7581                                                  query->data, "", NULL,
7582                                                  &(tbinfo->dobj.dumpId), 1,
7583                                                  NULL, NULL);
7584                 }
7585
7586                 comments++;
7587                 ncomments--;
7588         }
7589
7590         destroyPQExpBuffer(query);
7591         destroyPQExpBuffer(target);
7592 }
7593
7594 /*
7595  * findComments --
7596  *
7597  * Find the comment(s), if any, associated with the given object.  All the
7598  * objsubid values associated with the given classoid/objoid are found with
7599  * one search.
7600  */
7601 static int
7602 findComments(Archive *fout, Oid classoid, Oid objoid,
7603                          CommentItem **items)
7604 {
7605         /* static storage for table of comments */
7606         static CommentItem *comments = NULL;
7607         static int      ncomments = -1;
7608
7609         CommentItem *middle = NULL;
7610         CommentItem *low;
7611         CommentItem *high;
7612         int                     nmatch;
7613
7614         /* Get comments if we didn't already */
7615         if (ncomments < 0)
7616                 ncomments = collectComments(fout, &comments);
7617
7618         /*
7619          * Pre-7.2, pg_description does not contain classoid, so collectComments
7620          * just stores a zero.  If there's a collision on object OID, well, you
7621          * get duplicate comments.
7622          */
7623         if (fout->remoteVersion < 70200)
7624                 classoid = 0;
7625
7626         /*
7627          * Do binary search to find some item matching the object.
7628          */
7629         low = &comments[0];
7630         high = &comments[ncomments - 1];
7631         while (low <= high)
7632         {
7633                 middle = low + (high - low) / 2;
7634
7635                 if (classoid < middle->classoid)
7636                         high = middle - 1;
7637                 else if (classoid > middle->classoid)
7638                         low = middle + 1;
7639                 else if (objoid < middle->objoid)
7640                         high = middle - 1;
7641                 else if (objoid > middle->objoid)
7642                         low = middle + 1;
7643                 else
7644                         break;                          /* found a match */
7645         }
7646
7647         if (low > high)                         /* no matches */
7648         {
7649                 *items = NULL;
7650                 return 0;
7651         }
7652
7653         /*
7654          * Now determine how many items match the object.  The search loop
7655          * invariant still holds: only items between low and high inclusive could
7656          * match.
7657          */
7658         nmatch = 1;
7659         while (middle > low)
7660         {
7661                 if (classoid != middle[-1].classoid ||
7662                         objoid != middle[-1].objoid)
7663                         break;
7664                 middle--;
7665                 nmatch++;
7666         }
7667
7668         *items = middle;
7669
7670         middle += nmatch;
7671         while (middle <= high)
7672         {
7673                 if (classoid != middle->classoid ||
7674                         objoid != middle->objoid)
7675                         break;
7676                 middle++;
7677                 nmatch++;
7678         }
7679
7680         return nmatch;
7681 }
7682
7683 /*
7684  * collectComments --
7685  *
7686  * Construct a table of all comments available for database objects.
7687  * We used to do per-object queries for the comments, but it's much faster
7688  * to pull them all over at once, and on most databases the memory cost
7689  * isn't high.
7690  *
7691  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7692  */
7693 static int
7694 collectComments(Archive *fout, CommentItem **items)
7695 {
7696         PGresult   *res;
7697         PQExpBuffer query;
7698         int                     i_description;
7699         int                     i_classoid;
7700         int                     i_objoid;
7701         int                     i_objsubid;
7702         int                     ntups;
7703         int                     i;
7704         CommentItem *comments;
7705
7706         /*
7707          * Note we do NOT change source schema here; preserve the caller's
7708          * setting, instead.
7709          */
7710
7711         query = createPQExpBuffer();
7712
7713         if (fout->remoteVersion >= 70300)
7714         {
7715                 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
7716                                                          "FROM pg_catalog.pg_description "
7717                                                          "ORDER BY classoid, objoid, objsubid");
7718         }
7719         else if (fout->remoteVersion >= 70200)
7720         {
7721                 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
7722                                                          "FROM pg_description "
7723                                                          "ORDER BY classoid, objoid, objsubid");
7724         }
7725         else
7726         {
7727                 /* Note: this will fail to find attribute comments in pre-7.2... */
7728                 appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7729                                                          "FROM pg_description "
7730                                                          "ORDER BY objoid");
7731         }
7732
7733         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7734
7735         /* Construct lookup table containing OIDs in numeric form */
7736
7737         i_description = PQfnumber(res, "description");
7738         i_classoid = PQfnumber(res, "classoid");
7739         i_objoid = PQfnumber(res, "objoid");
7740         i_objsubid = PQfnumber(res, "objsubid");
7741
7742         ntups = PQntuples(res);
7743
7744         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7745
7746         for (i = 0; i < ntups; i++)
7747         {
7748                 comments[i].descr = PQgetvalue(res, i, i_description);
7749                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7750                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7751                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7752         }
7753
7754         /* Do NOT free the PGresult since we are keeping pointers into it */
7755         destroyPQExpBuffer(query);
7756
7757         *items = comments;
7758         return ntups;
7759 }
7760
7761 /*
7762  * dumpDumpableObject
7763  *
7764  * This routine and its subsidiaries are responsible for creating
7765  * ArchiveEntries (TOC objects) for each object to be dumped.
7766  */
7767 static void
7768 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7769 {
7770         switch (dobj->objType)
7771         {
7772                 case DO_NAMESPACE:
7773                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7774                         break;
7775                 case DO_EXTENSION:
7776                         dumpExtension(fout, (ExtensionInfo *) dobj);
7777                         break;
7778                 case DO_TYPE:
7779                         dumpType(fout, (TypeInfo *) dobj);
7780                         break;
7781                 case DO_SHELL_TYPE:
7782                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7783                         break;
7784                 case DO_FUNC:
7785                         dumpFunc(fout, (FuncInfo *) dobj);
7786                         break;
7787                 case DO_AGG:
7788                         dumpAgg(fout, (AggInfo *) dobj);
7789                         break;
7790                 case DO_OPERATOR:
7791                         dumpOpr(fout, (OprInfo *) dobj);
7792                         break;
7793                 case DO_OPCLASS:
7794                         dumpOpclass(fout, (OpclassInfo *) dobj);
7795                         break;
7796                 case DO_OPFAMILY:
7797                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7798                         break;
7799                 case DO_COLLATION:
7800                         dumpCollation(fout, (CollInfo *) dobj);
7801                         break;
7802                 case DO_CONVERSION:
7803                         dumpConversion(fout, (ConvInfo *) dobj);
7804                         break;
7805                 case DO_TABLE:
7806                         dumpTable(fout, (TableInfo *) dobj);
7807                         break;
7808                 case DO_ATTRDEF:
7809                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7810                         break;
7811                 case DO_INDEX:
7812                         dumpIndex(fout, (IndxInfo *) dobj);
7813                         break;
7814                 case DO_REFRESH_MATVIEW:
7815                         refreshMatViewData(fout, (TableDataInfo *) dobj);
7816                         break;
7817                 case DO_RULE:
7818                         dumpRule(fout, (RuleInfo *) dobj);
7819                         break;
7820                 case DO_TRIGGER:
7821                         dumpTrigger(fout, (TriggerInfo *) dobj);
7822                         break;
7823                 case DO_EVENT_TRIGGER:
7824                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7825                         break;
7826                 case DO_CONSTRAINT:
7827                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7828                         break;
7829                 case DO_FK_CONSTRAINT:
7830                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7831                         break;
7832                 case DO_PROCLANG:
7833                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7834                         break;
7835                 case DO_CAST:
7836                         dumpCast(fout, (CastInfo *) dobj);
7837                         break;
7838                 case DO_TABLE_DATA:
7839                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
7840                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
7841                         else
7842                                 dumpTableData(fout, (TableDataInfo *) dobj);
7843                         break;
7844                 case DO_DUMMY_TYPE:
7845                         /* table rowtypes and array types are never dumped separately */
7846                         break;
7847                 case DO_TSPARSER:
7848                         dumpTSParser(fout, (TSParserInfo *) dobj);
7849                         break;
7850                 case DO_TSDICT:
7851                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7852                         break;
7853                 case DO_TSTEMPLATE:
7854                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7855                         break;
7856                 case DO_TSCONFIG:
7857                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7858                         break;
7859                 case DO_FDW:
7860                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7861                         break;
7862                 case DO_FOREIGN_SERVER:
7863                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7864                         break;
7865                 case DO_DEFAULT_ACL:
7866                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7867                         break;
7868                 case DO_BLOB:
7869                         dumpBlob(fout, (BlobInfo *) dobj);
7870                         break;
7871                 case DO_BLOB_DATA:
7872                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7873                                                  dobj->name, NULL, NULL, "",
7874                                                  false, "BLOBS", SECTION_DATA,
7875                                                  "", "", NULL,
7876                                                  NULL, 0,
7877                                                  dumpBlobs, NULL);
7878                         break;
7879                 case DO_PRE_DATA_BOUNDARY:
7880                 case DO_POST_DATA_BOUNDARY:
7881                         /* never dumped, nothing to do */
7882                         break;
7883         }
7884 }
7885
7886 /*
7887  * dumpNamespace
7888  *        writes out to fout the queries to recreate a user-defined namespace
7889  */
7890 static void
7891 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7892 {
7893         PQExpBuffer q;
7894         PQExpBuffer delq;
7895         PQExpBuffer labelq;
7896         char       *qnspname;
7897
7898         /* Skip if not to be dumped */
7899         if (!nspinfo->dobj.dump || dataOnly)
7900                 return;
7901
7902         /* don't dump dummy namespace from pre-7.3 source */
7903         if (strlen(nspinfo->dobj.name) == 0)
7904                 return;
7905
7906         q = createPQExpBuffer();
7907         delq = createPQExpBuffer();
7908         labelq = createPQExpBuffer();
7909
7910         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7911
7912         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7913
7914         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7915
7916         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7917
7918         if (binary_upgrade)
7919                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7920
7921         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7922                                  nspinfo->dobj.name,
7923                                  NULL, NULL,
7924                                  nspinfo->rolname,
7925                                  false, "SCHEMA", SECTION_PRE_DATA,
7926                                  q->data, delq->data, NULL,
7927                                  NULL, 0,
7928                                  NULL, NULL);
7929
7930         /* Dump Schema Comments and Security Labels */
7931         dumpComment(fout, labelq->data,
7932                                 NULL, nspinfo->rolname,
7933                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7934         dumpSecLabel(fout, labelq->data,
7935                                  NULL, nspinfo->rolname,
7936                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7937
7938         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7939                         qnspname, NULL, nspinfo->dobj.name, NULL,
7940                         nspinfo->rolname, nspinfo->nspacl);
7941
7942         free(qnspname);
7943
7944         destroyPQExpBuffer(q);
7945         destroyPQExpBuffer(delq);
7946         destroyPQExpBuffer(labelq);
7947 }
7948
7949 /*
7950  * dumpExtension
7951  *        writes out to fout the queries to recreate an extension
7952  */
7953 static void
7954 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7955 {
7956         PQExpBuffer q;
7957         PQExpBuffer delq;
7958         PQExpBuffer labelq;
7959         char       *qextname;
7960
7961         /* Skip if not to be dumped */
7962         if (!extinfo->dobj.dump || dataOnly)
7963                 return;
7964
7965         q = createPQExpBuffer();
7966         delq = createPQExpBuffer();
7967         labelq = createPQExpBuffer();
7968
7969         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7970
7971         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7972
7973         if (!binary_upgrade)
7974         {
7975                 /*
7976                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7977                  * problem if the extension already exists in the target database;
7978                  * this is essential for installed-by-default extensions such as
7979                  * plpgsql.
7980                  *
7981                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7982                  * built-in extensions based on their OIDs; see
7983                  * selectDumpableExtension.
7984                  */
7985                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7986                                                   qextname, fmtId(extinfo->namespace));
7987         }
7988         else
7989         {
7990                 int                     i;
7991                 int                     n;
7992
7993                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7994
7995                 /*
7996                  * We unconditionally create the extension, so we must drop it if it
7997                  * exists.      This could happen if the user deleted 'plpgsql' and then
7998                  * readded it, causing its oid to be greater than FirstNormalObjectId.
7999                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
8000                  * and recreating extensions like 'plpgsql'.
8001                  */
8002                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
8003
8004                 appendPQExpBufferStr(q,
8005                                                   "SELECT binary_upgrade.create_empty_extension(");
8006                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
8007                 appendPQExpBufferStr(q, ", ");
8008                 appendStringLiteralAH(q, extinfo->namespace, fout);
8009                 appendPQExpBufferStr(q, ", ");
8010                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
8011                 appendStringLiteralAH(q, extinfo->extversion, fout);
8012                 appendPQExpBufferStr(q, ", ");
8013
8014                 /*
8015                  * Note that we're pushing extconfig (an OID array) back into
8016                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
8017                  * preserved in binary upgrade.
8018                  */
8019                 if (strlen(extinfo->extconfig) > 2)
8020                         appendStringLiteralAH(q, extinfo->extconfig, fout);
8021                 else
8022                         appendPQExpBufferStr(q, "NULL");
8023                 appendPQExpBufferStr(q, ", ");
8024                 if (strlen(extinfo->extcondition) > 2)
8025                         appendStringLiteralAH(q, extinfo->extcondition, fout);
8026                 else
8027                         appendPQExpBufferStr(q, "NULL");
8028                 appendPQExpBufferStr(q, ", ");
8029                 appendPQExpBufferStr(q, "ARRAY[");
8030                 n = 0;
8031                 for (i = 0; i < extinfo->dobj.nDeps; i++)
8032                 {
8033                         DumpableObject *extobj;
8034
8035                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
8036                         if (extobj && extobj->objType == DO_EXTENSION)
8037                         {
8038                                 if (n++ > 0)
8039                                         appendPQExpBufferChar(q, ',');
8040                                 appendStringLiteralAH(q, extobj->name, fout);
8041                         }
8042                 }
8043                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
8044                 appendPQExpBufferStr(q, ");\n");
8045         }
8046
8047         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
8048
8049         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
8050                                  extinfo->dobj.name,
8051                                  NULL, NULL,
8052                                  "",
8053                                  false, "EXTENSION", SECTION_PRE_DATA,
8054                                  q->data, delq->data, NULL,
8055                                  NULL, 0,
8056                                  NULL, NULL);
8057
8058         /* Dump Extension Comments and Security Labels */
8059         dumpComment(fout, labelq->data,
8060                                 NULL, "",
8061                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8062         dumpSecLabel(fout, labelq->data,
8063                                  NULL, "",
8064                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8065
8066         free(qextname);
8067
8068         destroyPQExpBuffer(q);
8069         destroyPQExpBuffer(delq);
8070         destroyPQExpBuffer(labelq);
8071 }
8072
8073 /*
8074  * dumpType
8075  *        writes out to fout the queries to recreate a user-defined type
8076  */
8077 static void
8078 dumpType(Archive *fout, TypeInfo *tyinfo)
8079 {
8080         /* Skip if not to be dumped */
8081         if (!tyinfo->dobj.dump || dataOnly)
8082                 return;
8083
8084         /* Dump out in proper style */
8085         if (tyinfo->typtype == TYPTYPE_BASE)
8086                 dumpBaseType(fout, tyinfo);
8087         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
8088                 dumpDomain(fout, tyinfo);
8089         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
8090                 dumpCompositeType(fout, tyinfo);
8091         else if (tyinfo->typtype == TYPTYPE_ENUM)
8092                 dumpEnumType(fout, tyinfo);
8093         else if (tyinfo->typtype == TYPTYPE_RANGE)
8094                 dumpRangeType(fout, tyinfo);
8095         else
8096                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
8097                                   tyinfo->dobj.name);
8098 }
8099
8100 /*
8101  * dumpEnumType
8102  *        writes out to fout the queries to recreate a user-defined enum type
8103  */
8104 static void
8105 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
8106 {
8107         PQExpBuffer q = createPQExpBuffer();
8108         PQExpBuffer delq = createPQExpBuffer();
8109         PQExpBuffer labelq = createPQExpBuffer();
8110         PQExpBuffer query = createPQExpBuffer();
8111         PGresult   *res;
8112         int                     num,
8113                                 i;
8114         Oid                     enum_oid;
8115         char       *qtypname;
8116         char       *label;
8117
8118         /* Set proper schema search path */
8119         selectSourceSchema(fout, "pg_catalog");
8120
8121         if (fout->remoteVersion >= 90100)
8122                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8123                                                   "FROM pg_catalog.pg_enum "
8124                                                   "WHERE enumtypid = '%u'"
8125                                                   "ORDER BY enumsortorder",
8126                                                   tyinfo->dobj.catId.oid);
8127         else
8128                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8129                                                   "FROM pg_catalog.pg_enum "
8130                                                   "WHERE enumtypid = '%u'"
8131                                                   "ORDER BY oid",
8132                                                   tyinfo->dobj.catId.oid);
8133
8134         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8135
8136         num = PQntuples(res);
8137
8138         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8139
8140         /*
8141          * DROP must be fully qualified in case same name appears in pg_catalog.
8142          * CASCADE shouldn't be required here as for normal types since the I/O
8143          * functions are generic and do not get dropped.
8144          */
8145         appendPQExpBuffer(delq, "DROP TYPE %s.",
8146                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8147         appendPQExpBuffer(delq, "%s;\n",
8148                                           qtypname);
8149
8150         if (binary_upgrade)
8151                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8152                                                                                                  tyinfo->dobj.catId.oid);
8153
8154         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8155                                           qtypname);
8156
8157         if (!binary_upgrade)
8158         {
8159                 /* Labels with server-assigned oids */
8160                 for (i = 0; i < num; i++)
8161                 {
8162                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8163                         if (i > 0)
8164                                 appendPQExpBufferChar(q, ',');
8165                         appendPQExpBufferStr(q, "\n    ");
8166                         appendStringLiteralAH(q, label, fout);
8167                 }
8168         }
8169
8170         appendPQExpBufferStr(q, "\n);\n");
8171
8172         if (binary_upgrade)
8173         {
8174                 /* Labels with dump-assigned (preserved) oids */
8175                 for (i = 0; i < num; i++)
8176                 {
8177                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8178                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8179
8180                         if (i == 0)
8181                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8182                         appendPQExpBuffer(q,
8183                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8184                                                           enum_oid);
8185                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8186                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8187                         appendPQExpBuffer(q, "%s ADD VALUE ",
8188                                                           qtypname);
8189                         appendStringLiteralAH(q, label, fout);
8190                         appendPQExpBufferStr(q, ";\n\n");
8191                 }
8192         }
8193
8194         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8195
8196         if (binary_upgrade)
8197                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8198
8199         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8200                                  tyinfo->dobj.name,
8201                                  tyinfo->dobj.namespace->dobj.name,
8202                                  NULL,
8203                                  tyinfo->rolname, false,
8204                                  "TYPE", SECTION_PRE_DATA,
8205                                  q->data, delq->data, NULL,
8206                                  NULL, 0,
8207                                  NULL, NULL);
8208
8209         /* Dump Type Comments and Security Labels */
8210         dumpComment(fout, labelq->data,
8211                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8212                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8213         dumpSecLabel(fout, labelq->data,
8214                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8215                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8216
8217         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8218                         qtypname, NULL, tyinfo->dobj.name,
8219                         tyinfo->dobj.namespace->dobj.name,
8220                         tyinfo->rolname, tyinfo->typacl);
8221
8222         PQclear(res);
8223         destroyPQExpBuffer(q);
8224         destroyPQExpBuffer(delq);
8225         destroyPQExpBuffer(labelq);
8226         destroyPQExpBuffer(query);
8227 }
8228
8229 /*
8230  * dumpRangeType
8231  *        writes out to fout the queries to recreate a user-defined range type
8232  */
8233 static void
8234 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
8235 {
8236         PQExpBuffer q = createPQExpBuffer();
8237         PQExpBuffer delq = createPQExpBuffer();
8238         PQExpBuffer labelq = createPQExpBuffer();
8239         PQExpBuffer query = createPQExpBuffer();
8240         PGresult   *res;
8241         Oid                     collationOid;
8242         char       *qtypname;
8243         char       *procname;
8244
8245         /*
8246          * select appropriate schema to ensure names in CREATE are properly
8247          * qualified
8248          */
8249         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8250
8251         appendPQExpBuffer(query,
8252                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8253                                           "opc.opcname AS opcname, "
8254                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8255                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8256                                           "opc.opcdefault, "
8257                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8258                                           "     ELSE rngcollation END AS collation, "
8259                                           "rngcanonical, rngsubdiff "
8260                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8261                                           "     pg_catalog.pg_opclass opc "
8262                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8263                                           "rngtypid = '%u'",
8264                                           tyinfo->dobj.catId.oid);
8265
8266         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8267
8268         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8269
8270         /*
8271          * DROP must be fully qualified in case same name appears in pg_catalog.
8272          * CASCADE shouldn't be required here as for normal types since the I/O
8273          * functions are generic and do not get dropped.
8274          */
8275         appendPQExpBuffer(delq, "DROP TYPE %s.",
8276                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8277         appendPQExpBuffer(delq, "%s;\n",
8278                                           qtypname);
8279
8280         if (binary_upgrade)
8281                 binary_upgrade_set_type_oids_by_type_oid(fout,
8282                                                                                                  q, tyinfo->dobj.catId.oid);
8283
8284         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8285                                           qtypname);
8286
8287         appendPQExpBuffer(q, "\n    subtype = %s",
8288                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8289
8290         /* print subtype_opclass only if not default for subtype */
8291         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8292         {
8293                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8294                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8295
8296                 /* always schema-qualify, don't try to be smart */
8297                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8298                                                   fmtId(nspname));
8299                 appendPQExpBufferStr(q, fmtId(opcname));
8300         }
8301
8302         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8303         if (OidIsValid(collationOid))
8304         {
8305                 CollInfo   *coll = findCollationByOid(collationOid);
8306
8307                 if (coll)
8308                 {
8309                         /* always schema-qualify, don't try to be smart */
8310                         appendPQExpBuffer(q, ",\n    collation = %s.",
8311                                                           fmtId(coll->dobj.namespace->dobj.name));
8312                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
8313                 }
8314         }
8315
8316         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8317         if (strcmp(procname, "-") != 0)
8318                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8319
8320         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8321         if (strcmp(procname, "-") != 0)
8322                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8323
8324         appendPQExpBufferStr(q, "\n);\n");
8325
8326         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8327
8328         if (binary_upgrade)
8329                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8330
8331         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8332                                  tyinfo->dobj.name,
8333                                  tyinfo->dobj.namespace->dobj.name,
8334                                  NULL,
8335                                  tyinfo->rolname, false,
8336                                  "TYPE", SECTION_PRE_DATA,
8337                                  q->data, delq->data, NULL,
8338                                  NULL, 0,
8339                                  NULL, NULL);
8340
8341         /* Dump Type Comments and Security Labels */
8342         dumpComment(fout, labelq->data,
8343                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8344                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8345         dumpSecLabel(fout, labelq->data,
8346                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8347                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8348
8349         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8350                         qtypname, NULL, tyinfo->dobj.name,
8351                         tyinfo->dobj.namespace->dobj.name,
8352                         tyinfo->rolname, tyinfo->typacl);
8353
8354         PQclear(res);
8355         destroyPQExpBuffer(q);
8356         destroyPQExpBuffer(delq);
8357         destroyPQExpBuffer(labelq);
8358         destroyPQExpBuffer(query);
8359 }
8360
8361 /*
8362  * dumpBaseType
8363  *        writes out to fout the queries to recreate a user-defined base type
8364  */
8365 static void
8366 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
8367 {
8368         PQExpBuffer q = createPQExpBuffer();
8369         PQExpBuffer delq = createPQExpBuffer();
8370         PQExpBuffer labelq = createPQExpBuffer();
8371         PQExpBuffer query = createPQExpBuffer();
8372         PGresult   *res;
8373         char       *qtypname;
8374         char       *typlen;
8375         char       *typinput;
8376         char       *typoutput;
8377         char       *typreceive;
8378         char       *typsend;
8379         char       *typmodin;
8380         char       *typmodout;
8381         char       *typanalyze;
8382         Oid                     typreceiveoid;
8383         Oid                     typsendoid;
8384         Oid                     typmodinoid;
8385         Oid                     typmodoutoid;
8386         Oid                     typanalyzeoid;
8387         char       *typcategory;
8388         char       *typispreferred;
8389         char       *typdelim;
8390         char       *typbyval;
8391         char       *typalign;
8392         char       *typstorage;
8393         char       *typcollatable;
8394         char       *typdefault;
8395         bool            typdefault_is_literal = false;
8396
8397         /* Set proper schema search path so regproc references list correctly */
8398         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8399
8400         /* Fetch type-specific details */
8401         if (fout->remoteVersion >= 90100)
8402         {
8403                 appendPQExpBuffer(query, "SELECT typlen, "
8404                                                   "typinput, typoutput, typreceive, typsend, "
8405                                                   "typmodin, typmodout, typanalyze, "
8406                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8407                                                   "typsend::pg_catalog.oid AS typsendoid, "
8408                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8409                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8410                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8411                                                   "typcategory, typispreferred, "
8412                                                   "typdelim, typbyval, typalign, typstorage, "
8413                                                   "(typcollation <> 0) AS typcollatable, "
8414                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8415                                                   "FROM pg_catalog.pg_type "
8416                                                   "WHERE oid = '%u'::pg_catalog.oid",
8417                                                   tyinfo->dobj.catId.oid);
8418         }
8419         else if (fout->remoteVersion >= 80400)
8420         {
8421                 appendPQExpBuffer(query, "SELECT typlen, "
8422                                                   "typinput, typoutput, typreceive, typsend, "
8423                                                   "typmodin, typmodout, typanalyze, "
8424                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8425                                                   "typsend::pg_catalog.oid AS typsendoid, "
8426                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8427                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8428                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8429                                                   "typcategory, typispreferred, "
8430                                                   "typdelim, typbyval, typalign, typstorage, "
8431                                                   "false AS typcollatable, "
8432                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8433                                                   "FROM pg_catalog.pg_type "
8434                                                   "WHERE oid = '%u'::pg_catalog.oid",
8435                                                   tyinfo->dobj.catId.oid);
8436         }
8437         else if (fout->remoteVersion >= 80300)
8438         {
8439                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8440                 appendPQExpBuffer(query, "SELECT typlen, "
8441                                                   "typinput, typoutput, typreceive, typsend, "
8442                                                   "typmodin, typmodout, typanalyze, "
8443                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8444                                                   "typsend::pg_catalog.oid AS typsendoid, "
8445                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8446                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8447                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8448                                                   "'U' AS typcategory, false AS typispreferred, "
8449                                                   "typdelim, typbyval, typalign, typstorage, "
8450                                                   "false AS typcollatable, "
8451                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8452                                                   "FROM pg_catalog.pg_type "
8453                                                   "WHERE oid = '%u'::pg_catalog.oid",
8454                                                   tyinfo->dobj.catId.oid);
8455         }
8456         else if (fout->remoteVersion >= 80000)
8457         {
8458                 appendPQExpBuffer(query, "SELECT typlen, "
8459                                                   "typinput, typoutput, typreceive, typsend, "
8460                                                   "'-' AS typmodin, '-' AS typmodout, "
8461                                                   "typanalyze, "
8462                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8463                                                   "typsend::pg_catalog.oid AS typsendoid, "
8464                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8465                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8466                                                   "'U' AS typcategory, false AS typispreferred, "
8467                                                   "typdelim, typbyval, typalign, typstorage, "
8468                                                   "false AS typcollatable, "
8469                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8470                                                   "FROM pg_catalog.pg_type "
8471                                                   "WHERE oid = '%u'::pg_catalog.oid",
8472                                                   tyinfo->dobj.catId.oid);
8473         }
8474         else if (fout->remoteVersion >= 70400)
8475         {
8476                 appendPQExpBuffer(query, "SELECT typlen, "
8477                                                   "typinput, typoutput, typreceive, typsend, "
8478                                                   "'-' AS typmodin, '-' AS typmodout, "
8479                                                   "'-' AS typanalyze, "
8480                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8481                                                   "typsend::pg_catalog.oid AS typsendoid, "
8482                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8483                                                   "0 AS typanalyzeoid, "
8484                                                   "'U' AS typcategory, false AS typispreferred, "
8485                                                   "typdelim, typbyval, typalign, typstorage, "
8486                                                   "false AS typcollatable, "
8487                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8488                                                   "FROM pg_catalog.pg_type "
8489                                                   "WHERE oid = '%u'::pg_catalog.oid",
8490                                                   tyinfo->dobj.catId.oid);
8491         }
8492         else if (fout->remoteVersion >= 70300)
8493         {
8494                 appendPQExpBuffer(query, "SELECT typlen, "
8495                                                   "typinput, typoutput, "
8496                                                   "'-' AS typreceive, '-' AS typsend, "
8497                                                   "'-' AS typmodin, '-' AS typmodout, "
8498                                                   "'-' AS typanalyze, "
8499                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8500                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8501                                                   "0 AS typanalyzeoid, "
8502                                                   "'U' AS typcategory, false AS typispreferred, "
8503                                                   "typdelim, typbyval, typalign, typstorage, "
8504                                                   "false AS typcollatable, "
8505                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8506                                                   "FROM pg_catalog.pg_type "
8507                                                   "WHERE oid = '%u'::pg_catalog.oid",
8508                                                   tyinfo->dobj.catId.oid);
8509         }
8510         else if (fout->remoteVersion >= 70200)
8511         {
8512                 /*
8513                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8514                  * ignore them because they are not right.
8515                  */
8516                 appendPQExpBuffer(query, "SELECT typlen, "
8517                                                   "typinput, typoutput, "
8518                                                   "'-' AS typreceive, '-' AS typsend, "
8519                                                   "'-' AS typmodin, '-' AS typmodout, "
8520                                                   "'-' AS typanalyze, "
8521                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8522                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8523                                                   "0 AS typanalyzeoid, "
8524                                                   "'U' AS typcategory, false AS typispreferred, "
8525                                                   "typdelim, typbyval, typalign, typstorage, "
8526                                                   "false AS typcollatable, "
8527                                                   "NULL AS typdefaultbin, typdefault "
8528                                                   "FROM pg_type "
8529                                                   "WHERE oid = '%u'::oid",
8530                                                   tyinfo->dobj.catId.oid);
8531         }
8532         else if (fout->remoteVersion >= 70100)
8533         {
8534                 /*
8535                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8536                  * representation.
8537                  */
8538                 appendPQExpBuffer(query, "SELECT typlen, "
8539                                                   "typinput, typoutput, "
8540                                                   "'-' AS typreceive, '-' AS typsend, "
8541                                                   "'-' AS typmodin, '-' AS typmodout, "
8542                                                   "'-' AS typanalyze, "
8543                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8544                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8545                                                   "0 AS typanalyzeoid, "
8546                                                   "'U' AS typcategory, false AS typispreferred, "
8547                                                   "typdelim, typbyval, typalign, typstorage, "
8548                                                   "false AS typcollatable, "
8549                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8550                                                   "FROM pg_type "
8551                                                   "WHERE oid = '%u'::oid",
8552                                                   tyinfo->dobj.catId.oid);
8553         }
8554         else
8555         {
8556                 appendPQExpBuffer(query, "SELECT typlen, "
8557                                                   "typinput, typoutput, "
8558                                                   "'-' AS typreceive, '-' AS typsend, "
8559                                                   "'-' AS typmodin, '-' AS typmodout, "
8560                                                   "'-' AS typanalyze, "
8561                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8562                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8563                                                   "0 AS typanalyzeoid, "
8564                                                   "'U' AS typcategory, false AS typispreferred, "
8565                                                   "typdelim, typbyval, typalign, "
8566                                                   "'p'::char AS typstorage, "
8567                                                   "false AS typcollatable, "
8568                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8569                                                   "FROM pg_type "
8570                                                   "WHERE oid = '%u'::oid",
8571                                                   tyinfo->dobj.catId.oid);
8572         }
8573
8574         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8575
8576         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8577         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8578         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8579         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8580         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8581         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8582         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8583         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8584         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8585         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8586         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8587         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8588         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8589         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8590         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8591         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8592         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8593         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8594         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8595         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8596         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8597                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8598         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8599         {
8600                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8601                 typdefault_is_literal = true;   /* it needs quotes */
8602         }
8603         else
8604                 typdefault = NULL;
8605
8606         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8607
8608         /*
8609          * DROP must be fully qualified in case same name appears in pg_catalog.
8610          * The reason we include CASCADE is that the circular dependency between
8611          * the type and its I/O functions makes it impossible to drop the type any
8612          * other way.
8613          */
8614         appendPQExpBuffer(delq, "DROP TYPE %s.",
8615                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8616         appendPQExpBuffer(delq, "%s CASCADE;\n",
8617                                           qtypname);
8618
8619         /* We might already have a shell type, but setting pg_type_oid is harmless */
8620         if (binary_upgrade)
8621                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8622                                                                                                  tyinfo->dobj.catId.oid);
8623
8624         appendPQExpBuffer(q,
8625                                           "CREATE TYPE %s (\n"
8626                                           "    INTERNALLENGTH = %s",
8627                                           qtypname,
8628                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8629
8630         if (fout->remoteVersion >= 70300)
8631         {
8632                 /* regproc result is correctly quoted as of 7.3 */
8633                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8634                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8635                 if (OidIsValid(typreceiveoid))
8636                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8637                 if (OidIsValid(typsendoid))
8638                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8639                 if (OidIsValid(typmodinoid))
8640                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8641                 if (OidIsValid(typmodoutoid))
8642                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8643                 if (OidIsValid(typanalyzeoid))
8644                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8645         }
8646         else
8647         {
8648                 /* regproc delivers an unquoted name before 7.3 */
8649                 /* cannot combine these because fmtId uses static result area */
8650                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8651                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8652                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8653         }
8654
8655         if (strcmp(typcollatable, "t") == 0)
8656                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
8657
8658         if (typdefault != NULL)
8659         {
8660                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
8661                 if (typdefault_is_literal)
8662                         appendStringLiteralAH(q, typdefault, fout);
8663                 else
8664                         appendPQExpBufferStr(q, typdefault);
8665         }
8666
8667         if (OidIsValid(tyinfo->typelem))
8668         {
8669                 char       *elemType;
8670
8671                 /* reselect schema in case changed by function dump */
8672                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8673                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8674                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8675                 free(elemType);
8676         }
8677
8678         if (strcmp(typcategory, "U") != 0)
8679         {
8680                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
8681                 appendStringLiteralAH(q, typcategory, fout);
8682         }
8683
8684         if (strcmp(typispreferred, "t") == 0)
8685                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
8686
8687         if (typdelim && strcmp(typdelim, ",") != 0)
8688         {
8689                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
8690                 appendStringLiteralAH(q, typdelim, fout);
8691         }
8692
8693         if (strcmp(typalign, "c") == 0)
8694                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
8695         else if (strcmp(typalign, "s") == 0)
8696                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
8697         else if (strcmp(typalign, "i") == 0)
8698                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
8699         else if (strcmp(typalign, "d") == 0)
8700                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
8701
8702         if (strcmp(typstorage, "p") == 0)
8703                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
8704         else if (strcmp(typstorage, "e") == 0)
8705                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
8706         else if (strcmp(typstorage, "x") == 0)
8707                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
8708         else if (strcmp(typstorage, "m") == 0)
8709                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
8710
8711         if (strcmp(typbyval, "t") == 0)
8712                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
8713
8714         appendPQExpBufferStr(q, "\n);\n");
8715
8716         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8717
8718         if (binary_upgrade)
8719                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8720
8721         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8722                                  tyinfo->dobj.name,
8723                                  tyinfo->dobj.namespace->dobj.name,
8724                                  NULL,
8725                                  tyinfo->rolname, false,
8726                                  "TYPE", SECTION_PRE_DATA,
8727                                  q->data, delq->data, NULL,
8728                                  NULL, 0,
8729                                  NULL, NULL);
8730
8731         /* Dump Type Comments and Security Labels */
8732         dumpComment(fout, labelq->data,
8733                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8734                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8735         dumpSecLabel(fout, labelq->data,
8736                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8737                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8738
8739         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8740                         qtypname, NULL, tyinfo->dobj.name,
8741                         tyinfo->dobj.namespace->dobj.name,
8742                         tyinfo->rolname, tyinfo->typacl);
8743
8744         PQclear(res);
8745         destroyPQExpBuffer(q);
8746         destroyPQExpBuffer(delq);
8747         destroyPQExpBuffer(labelq);
8748         destroyPQExpBuffer(query);
8749 }
8750
8751 /*
8752  * dumpDomain
8753  *        writes out to fout the queries to recreate a user-defined domain
8754  */
8755 static void
8756 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8757 {
8758         PQExpBuffer q = createPQExpBuffer();
8759         PQExpBuffer delq = createPQExpBuffer();
8760         PQExpBuffer labelq = createPQExpBuffer();
8761         PQExpBuffer query = createPQExpBuffer();
8762         PGresult   *res;
8763         int                     i;
8764         char       *qtypname;
8765         char       *typnotnull;
8766         char       *typdefn;
8767         char       *typdefault;
8768         Oid                     typcollation;
8769         bool            typdefault_is_literal = false;
8770
8771         /* Set proper schema search path so type references list correctly */
8772         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8773
8774         /* Fetch domain specific details */
8775         if (fout->remoteVersion >= 90100)
8776         {
8777                 /* typcollation is new in 9.1 */
8778                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8779                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8780                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8781                                                   "t.typdefault, "
8782                                                   "CASE WHEN t.typcollation <> u.typcollation "
8783                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8784                                                   "FROM pg_catalog.pg_type t "
8785                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8786                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8787                                                   tyinfo->dobj.catId.oid);
8788         }
8789         else
8790         {
8791                 /* We assume here that remoteVersion must be at least 70300 */
8792                 appendPQExpBuffer(query, "SELECT typnotnull, "
8793                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8794                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8795                                                   "typdefault, 0 AS typcollation "
8796                                                   "FROM pg_catalog.pg_type "
8797                                                   "WHERE oid = '%u'::pg_catalog.oid",
8798                                                   tyinfo->dobj.catId.oid);
8799         }
8800
8801         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8802
8803         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8804         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8805         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8806                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8807         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8808         {
8809                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8810                 typdefault_is_literal = true;   /* it needs quotes */
8811         }
8812         else
8813                 typdefault = NULL;
8814         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8815
8816         if (binary_upgrade)
8817                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8818                                                                                                  tyinfo->dobj.catId.oid);
8819
8820         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8821
8822         appendPQExpBuffer(q,
8823                                           "CREATE DOMAIN %s AS %s",
8824                                           qtypname,
8825                                           typdefn);
8826
8827         /* Print collation only if different from base type's collation */
8828         if (OidIsValid(typcollation))
8829         {
8830                 CollInfo   *coll;
8831
8832                 coll = findCollationByOid(typcollation);
8833                 if (coll)
8834                 {
8835                         /* always schema-qualify, don't try to be smart */
8836                         appendPQExpBuffer(q, " COLLATE %s.",
8837                                                           fmtId(coll->dobj.namespace->dobj.name));
8838                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
8839                 }
8840         }
8841
8842         if (typnotnull[0] == 't')
8843                 appendPQExpBufferStr(q, " NOT NULL");
8844
8845         if (typdefault != NULL)
8846         {
8847                 appendPQExpBufferStr(q, " DEFAULT ");
8848                 if (typdefault_is_literal)
8849                         appendStringLiteralAH(q, typdefault, fout);
8850                 else
8851                         appendPQExpBufferStr(q, typdefault);
8852         }
8853
8854         PQclear(res);
8855
8856         /*
8857          * Add any CHECK constraints for the domain
8858          */
8859         for (i = 0; i < tyinfo->nDomChecks; i++)
8860         {
8861                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8862
8863                 if (!domcheck->separate)
8864                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8865                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8866         }
8867
8868         appendPQExpBufferStr(q, ";\n");
8869
8870         /*
8871          * DROP must be fully qualified in case same name appears in pg_catalog
8872          */
8873         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8874                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8875         appendPQExpBuffer(delq, "%s;\n",
8876                                           qtypname);
8877
8878         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
8879
8880         if (binary_upgrade)
8881                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8882
8883         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8884                                  tyinfo->dobj.name,
8885                                  tyinfo->dobj.namespace->dobj.name,
8886                                  NULL,
8887                                  tyinfo->rolname, false,
8888                                  "DOMAIN", SECTION_PRE_DATA,
8889                                  q->data, delq->data, NULL,
8890                                  NULL, 0,
8891                                  NULL, NULL);
8892
8893         /* Dump Domain Comments and Security Labels */
8894         dumpComment(fout, labelq->data,
8895                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8896                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8897         dumpSecLabel(fout, labelq->data,
8898                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8899                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8900
8901         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8902                         qtypname, NULL, tyinfo->dobj.name,
8903                         tyinfo->dobj.namespace->dobj.name,
8904                         tyinfo->rolname, tyinfo->typacl);
8905
8906         destroyPQExpBuffer(q);
8907         destroyPQExpBuffer(delq);
8908         destroyPQExpBuffer(labelq);
8909         destroyPQExpBuffer(query);
8910 }
8911
8912 /*
8913  * dumpCompositeType
8914  *        writes out to fout the queries to recreate a user-defined stand-alone
8915  *        composite type
8916  */
8917 static void
8918 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8919 {
8920         PQExpBuffer q = createPQExpBuffer();
8921         PQExpBuffer dropped = createPQExpBuffer();
8922         PQExpBuffer delq = createPQExpBuffer();
8923         PQExpBuffer labelq = createPQExpBuffer();
8924         PQExpBuffer query = createPQExpBuffer();
8925         PGresult   *res;
8926         char       *qtypname;
8927         int                     ntups;
8928         int                     i_attname;
8929         int                     i_atttypdefn;
8930         int                     i_attlen;
8931         int                     i_attalign;
8932         int                     i_attisdropped;
8933         int                     i_attcollation;
8934         int                     i_typrelid;
8935         int                     i;
8936         int                     actual_atts;
8937
8938         /* Set proper schema search path so type references list correctly */
8939         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8940
8941         /* Fetch type specific details */
8942         if (fout->remoteVersion >= 90100)
8943         {
8944                 /*
8945                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8946                  * clauses for attributes whose collation is different from their
8947                  * type's default, we use a CASE here to suppress uninteresting
8948                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8949                  * collation does not matter for those.
8950                  */
8951                 appendPQExpBuffer(query, "SELECT a.attname, "
8952                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8953                                                   "a.attlen, a.attalign, a.attisdropped, "
8954                                                   "CASE WHEN a.attcollation <> at.typcollation "
8955                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8956                                                   "ct.typrelid "
8957                                                   "FROM pg_catalog.pg_type ct "
8958                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8959                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8960                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8961                                                   "ORDER BY a.attnum ",
8962                                                   tyinfo->dobj.catId.oid);
8963         }
8964         else
8965         {
8966                 /*
8967                  * We assume here that remoteVersion must be at least 70300.  Since
8968                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8969                  * always be false.
8970                  */
8971                 appendPQExpBuffer(query, "SELECT a.attname, "
8972                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8973                                                   "a.attlen, a.attalign, a.attisdropped, "
8974                                                   "0 AS attcollation, "
8975                                                   "ct.typrelid "
8976                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8977                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8978                                                   "AND a.attrelid = ct.typrelid "
8979                                                   "ORDER BY a.attnum ",
8980                                                   tyinfo->dobj.catId.oid);
8981         }
8982
8983         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8984
8985         ntups = PQntuples(res);
8986
8987         i_attname = PQfnumber(res, "attname");
8988         i_atttypdefn = PQfnumber(res, "atttypdefn");
8989         i_attlen = PQfnumber(res, "attlen");
8990         i_attalign = PQfnumber(res, "attalign");
8991         i_attisdropped = PQfnumber(res, "attisdropped");
8992         i_attcollation = PQfnumber(res, "attcollation");
8993         i_typrelid = PQfnumber(res, "typrelid");
8994
8995         if (binary_upgrade)
8996         {
8997                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8998
8999                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9000                                                                                                  tyinfo->dobj.catId.oid);
9001                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
9002         }
9003
9004         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9005
9006         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
9007                                           qtypname);
9008
9009         actual_atts = 0;
9010         for (i = 0; i < ntups; i++)
9011         {
9012                 char       *attname;
9013                 char       *atttypdefn;
9014                 char       *attlen;
9015                 char       *attalign;
9016                 bool            attisdropped;
9017                 Oid                     attcollation;
9018
9019                 attname = PQgetvalue(res, i, i_attname);
9020                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
9021                 attlen = PQgetvalue(res, i, i_attlen);
9022                 attalign = PQgetvalue(res, i, i_attalign);
9023                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
9024                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
9025
9026                 if (attisdropped && !binary_upgrade)
9027                         continue;
9028
9029                 /* Format properly if not first attr */
9030                 if (actual_atts++ > 0)
9031                         appendPQExpBufferChar(q, ',');
9032                 appendPQExpBufferStr(q, "\n\t");
9033
9034                 if (!attisdropped)
9035                 {
9036                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
9037
9038                         /* Add collation if not default for the column type */
9039                         if (OidIsValid(attcollation))
9040                         {
9041                                 CollInfo   *coll;
9042
9043                                 coll = findCollationByOid(attcollation);
9044                                 if (coll)
9045                                 {
9046                                         /* always schema-qualify, don't try to be smart */
9047                                         appendPQExpBuffer(q, " COLLATE %s.",
9048                                                                           fmtId(coll->dobj.namespace->dobj.name));
9049                                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
9050                                 }
9051                         }
9052                 }
9053                 else
9054                 {
9055                         /*
9056                          * This is a dropped attribute and we're in binary_upgrade mode.
9057                          * Insert a placeholder for it in the CREATE TYPE command, and set
9058                          * length and alignment with direct UPDATE to the catalogs
9059                          * afterwards. See similar code in dumpTableSchema().
9060                          */
9061                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
9062
9063                         /* stash separately for insertion after the CREATE TYPE */
9064                         appendPQExpBufferStr(dropped,
9065                                           "\n-- For binary upgrade, recreate dropped column.\n");
9066                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
9067                                                           "SET attlen = %s, "
9068                                                           "attalign = '%s', attbyval = false\n"
9069                                                           "WHERE attname = ", attlen, attalign);
9070                         appendStringLiteralAH(dropped, attname, fout);
9071                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
9072                         appendStringLiteralAH(dropped, qtypname, fout);
9073                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
9074
9075                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
9076                                                           qtypname);
9077                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
9078                                                           fmtId(attname));
9079                 }
9080         }
9081         appendPQExpBufferStr(q, "\n);\n");
9082         appendPQExpBufferStr(q, dropped->data);
9083
9084         /*
9085          * DROP must be fully qualified in case same name appears in pg_catalog
9086          */
9087         appendPQExpBuffer(delq, "DROP TYPE %s.",
9088                                           fmtId(tyinfo->dobj.namespace->dobj.name));
9089         appendPQExpBuffer(delq, "%s;\n",
9090                                           qtypname);
9091
9092         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
9093
9094         if (binary_upgrade)
9095                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9096
9097         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9098                                  tyinfo->dobj.name,
9099                                  tyinfo->dobj.namespace->dobj.name,
9100                                  NULL,
9101                                  tyinfo->rolname, false,
9102                                  "TYPE", SECTION_PRE_DATA,
9103                                  q->data, delq->data, NULL,
9104                                  NULL, 0,
9105                                  NULL, NULL);
9106
9107
9108         /* Dump Type Comments and Security Labels */
9109         dumpComment(fout, labelq->data,
9110                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9111                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9112         dumpSecLabel(fout, labelq->data,
9113                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9114                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9115
9116         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9117                         qtypname, NULL, tyinfo->dobj.name,
9118                         tyinfo->dobj.namespace->dobj.name,
9119                         tyinfo->rolname, tyinfo->typacl);
9120
9121         PQclear(res);
9122         destroyPQExpBuffer(q);
9123         destroyPQExpBuffer(dropped);
9124         destroyPQExpBuffer(delq);
9125         destroyPQExpBuffer(labelq);
9126         destroyPQExpBuffer(query);
9127
9128         /* Dump any per-column comments */
9129         dumpCompositeTypeColComments(fout, tyinfo);
9130 }
9131
9132 /*
9133  * dumpCompositeTypeColComments
9134  *        writes out to fout the queries to recreate comments on the columns of
9135  *        a user-defined stand-alone composite type
9136  */
9137 static void
9138 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9139 {
9140         CommentItem *comments;
9141         int                     ncomments;
9142         PGresult   *res;
9143         PQExpBuffer query;
9144         PQExpBuffer target;
9145         Oid                     pgClassOid;
9146         int                     i;
9147         int                     ntups;
9148         int                     i_attname;
9149         int                     i_attnum;
9150
9151         query = createPQExpBuffer();
9152
9153         /* We assume here that remoteVersion must be at least 70300 */
9154         appendPQExpBuffer(query,
9155                                           "SELECT c.tableoid, a.attname, a.attnum "
9156                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9157                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9158                                           "  AND NOT a.attisdropped "
9159                                           "ORDER BY a.attnum ",
9160                                           tyinfo->typrelid);
9161
9162         /* Fetch column attnames */
9163         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9164
9165         ntups = PQntuples(res);
9166         if (ntups < 1)
9167         {
9168                 PQclear(res);
9169                 destroyPQExpBuffer(query);
9170                 return;
9171         }
9172
9173         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9174
9175         /* Search for comments associated with type's pg_class OID */
9176         ncomments = findComments(fout,
9177                                                          pgClassOid,
9178                                                          tyinfo->typrelid,
9179                                                          &comments);
9180
9181         /* If no comments exist, we're done */
9182         if (ncomments <= 0)
9183         {
9184                 PQclear(res);
9185                 destroyPQExpBuffer(query);
9186                 return;
9187         }
9188
9189         /* Build COMMENT ON statements */
9190         target = createPQExpBuffer();
9191
9192         i_attnum = PQfnumber(res, "attnum");
9193         i_attname = PQfnumber(res, "attname");
9194         while (ncomments > 0)
9195         {
9196                 const char *attname;
9197
9198                 attname = NULL;
9199                 for (i = 0; i < ntups; i++)
9200                 {
9201                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9202                         {
9203                                 attname = PQgetvalue(res, i, i_attname);
9204                                 break;
9205                         }
9206                 }
9207                 if (attname)                    /* just in case we don't find it */
9208                 {
9209                         const char *descr = comments->descr;
9210
9211                         resetPQExpBuffer(target);
9212                         appendPQExpBuffer(target, "COLUMN %s.",
9213                                                           fmtId(tyinfo->dobj.name));
9214                         appendPQExpBufferStr(target, fmtId(attname));
9215
9216                         resetPQExpBuffer(query);
9217                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9218                         appendStringLiteralAH(query, descr, fout);
9219                         appendPQExpBufferStr(query, ";\n");
9220
9221                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9222                                                  target->data,
9223                                                  tyinfo->dobj.namespace->dobj.name,
9224                                                  NULL, tyinfo->rolname,
9225                                                  false, "COMMENT", SECTION_NONE,
9226                                                  query->data, "", NULL,
9227                                                  &(tyinfo->dobj.dumpId), 1,
9228                                                  NULL, NULL);
9229                 }
9230
9231                 comments++;
9232                 ncomments--;
9233         }
9234
9235         PQclear(res);
9236         destroyPQExpBuffer(query);
9237         destroyPQExpBuffer(target);
9238 }
9239
9240 /*
9241  * dumpShellType
9242  *        writes out to fout the queries to create a shell type
9243  *
9244  * We dump a shell definition in advance of the I/O functions for the type.
9245  */
9246 static void
9247 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
9248 {
9249         PQExpBuffer q;
9250
9251         /* Skip if not to be dumped */
9252         if (!stinfo->dobj.dump || dataOnly)
9253                 return;
9254
9255         q = createPQExpBuffer();
9256
9257         /*
9258          * Note the lack of a DROP command for the shell type; any required DROP
9259          * is driven off the base type entry, instead.  This interacts with
9260          * _printTocEntry()'s use of the presence of a DROP command to decide
9261          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9262          * the shell type's owner immediately on creation; that should happen only
9263          * after it's filled in, otherwise the backend complains.
9264          */
9265
9266         if (binary_upgrade)
9267                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9268                                                                                    stinfo->baseType->dobj.catId.oid);
9269
9270         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9271                                           fmtId(stinfo->dobj.name));
9272
9273         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9274                                  stinfo->dobj.name,
9275                                  stinfo->dobj.namespace->dobj.name,
9276                                  NULL,
9277                                  stinfo->baseType->rolname, false,
9278                                  "SHELL TYPE", SECTION_PRE_DATA,
9279                                  q->data, "", NULL,
9280                                  NULL, 0,
9281                                  NULL, NULL);
9282
9283         destroyPQExpBuffer(q);
9284 }
9285
9286 /*
9287  * Determine whether we want to dump definitions for procedural languages.
9288  * Since the languages themselves don't have schemas, we can't rely on
9289  * the normal schema-based selection mechanism.  We choose to dump them
9290  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9291  * the dump flag of the PL's call handler function, but in 8.1 this will
9292  * probably always be false since call handlers are created in pg_catalog.)
9293  *
9294  * For some backwards compatibility with the older behavior, we forcibly
9295  * dump a PL if its handler function (and validator if any) are in a
9296  * dumpable namespace.  That case is not checked here.
9297  *
9298  * Also, if the PL belongs to an extension, we do not use this heuristic.
9299  * That case isn't checked here either.
9300  */
9301 static bool
9302 shouldDumpProcLangs(void)
9303 {
9304         if (!include_everything)
9305                 return false;
9306         /* And they're schema not data */
9307         if (dataOnly)
9308                 return false;
9309         return true;
9310 }
9311
9312 /*
9313  * dumpProcLang
9314  *                writes out to fout the queries to recreate a user-defined
9315  *                procedural language
9316  */
9317 static void
9318 dumpProcLang(Archive *fout, ProcLangInfo *plang)
9319 {
9320         PQExpBuffer defqry;
9321         PQExpBuffer delqry;
9322         PQExpBuffer labelq;
9323         bool            useParams;
9324         char       *qlanname;
9325         char       *lanschema;
9326         FuncInfo   *funcInfo;
9327         FuncInfo   *inlineInfo = NULL;
9328         FuncInfo   *validatorInfo = NULL;
9329
9330         /* Skip if not to be dumped */
9331         if (!plang->dobj.dump || dataOnly)
9332                 return;
9333
9334         /*
9335          * Try to find the support function(s).  It is not an error if we don't
9336          * find them --- if the functions are in the pg_catalog schema, as is
9337          * standard in 8.1 and up, then we won't have loaded them. (In this case
9338          * we will emit a parameterless CREATE LANGUAGE command, which will
9339          * require PL template knowledge in the backend to reload.)
9340          */
9341
9342         funcInfo = findFuncByOid(plang->lanplcallfoid);
9343         if (funcInfo != NULL && !funcInfo->dobj.dump)
9344                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9345
9346         if (OidIsValid(plang->laninline))
9347         {
9348                 inlineInfo = findFuncByOid(plang->laninline);
9349                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9350                         inlineInfo = NULL;
9351         }
9352
9353         if (OidIsValid(plang->lanvalidator))
9354         {
9355                 validatorInfo = findFuncByOid(plang->lanvalidator);
9356                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9357                         validatorInfo = NULL;
9358         }
9359
9360         /*
9361          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9362          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9363          * dump it.
9364          *
9365          * However, for a language that belongs to an extension, we must not use
9366          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9367          * told to (via dobj.dump).  Generally the support functions will belong
9368          * to the same extension and so have the same dump flags ... if they
9369          * don't, this might not work terribly nicely.
9370          */
9371         useParams = (funcInfo != NULL &&
9372                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9373                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9374
9375         if (!plang->dobj.ext_member)
9376         {
9377                 if (!useParams && !shouldDumpProcLangs())
9378                         return;
9379         }
9380
9381         defqry = createPQExpBuffer();
9382         delqry = createPQExpBuffer();
9383         labelq = createPQExpBuffer();
9384
9385         qlanname = pg_strdup(fmtId(plang->dobj.name));
9386
9387         /*
9388          * If dumping a HANDLER clause, treat the language as being in the handler
9389          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9390          * it doesn't really have a schema.
9391          */
9392         if (useParams)
9393                 lanschema = funcInfo->dobj.namespace->dobj.name;
9394         else
9395                 lanschema = NULL;
9396
9397         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9398                                           qlanname);
9399
9400         if (useParams)
9401         {
9402                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9403                                                   plang->lanpltrusted ? "TRUSTED " : "",
9404                                                   qlanname);
9405                 appendPQExpBuffer(defqry, " HANDLER %s",
9406                                                   fmtId(funcInfo->dobj.name));
9407                 if (OidIsValid(plang->laninline))
9408                 {
9409                         appendPQExpBufferStr(defqry, " INLINE ");
9410                         /* Cope with possibility that inline is in different schema */
9411                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9412                                 appendPQExpBuffer(defqry, "%s.",
9413                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9414                         appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name));
9415                 }
9416                 if (OidIsValid(plang->lanvalidator))
9417                 {
9418                         appendPQExpBufferStr(defqry, " VALIDATOR ");
9419                         /* Cope with possibility that validator is in different schema */
9420                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9421                                 appendPQExpBuffer(defqry, "%s.",
9422                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9423                         appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name));
9424                 }
9425         }
9426         else
9427         {
9428                 /*
9429                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9430                  * command will not fail if the language is preinstalled in the target
9431                  * database.  We restrict the use of REPLACE to this case so as to
9432                  * eliminate the risk of replacing a language with incompatible
9433                  * parameter settings: this command will only succeed at all if there
9434                  * is a pg_pltemplate entry, and if there is one, the existing entry
9435                  * must match it too.
9436                  */
9437                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9438                                                   qlanname);
9439         }
9440         appendPQExpBufferStr(defqry, ";\n");
9441
9442         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9443
9444         if (binary_upgrade)
9445                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9446
9447         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9448                                  plang->dobj.name,
9449                                  lanschema, NULL, plang->lanowner,
9450                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9451                                  defqry->data, delqry->data, NULL,
9452                                  NULL, 0,
9453                                  NULL, NULL);
9454
9455         /* Dump Proc Lang Comments and Security Labels */
9456         dumpComment(fout, labelq->data,
9457                                 NULL, "",
9458                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9459         dumpSecLabel(fout, labelq->data,
9460                                  NULL, "",
9461                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9462
9463         if (plang->lanpltrusted)
9464                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9465                                 qlanname, NULL, plang->dobj.name,
9466                                 lanschema,
9467                                 plang->lanowner, plang->lanacl);
9468
9469         free(qlanname);
9470
9471         destroyPQExpBuffer(defqry);
9472         destroyPQExpBuffer(delqry);
9473         destroyPQExpBuffer(labelq);
9474 }
9475
9476 /*
9477  * format_function_arguments: generate function name and argument list
9478  *
9479  * This is used when we can rely on pg_get_function_arguments to format
9480  * the argument list.  Note, however, that pg_get_function_arguments
9481  * does not special-case zero-argument aggregates.
9482  */
9483 static char *
9484 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
9485 {
9486         PQExpBufferData fn;
9487
9488         initPQExpBuffer(&fn);
9489         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
9490         if (is_agg && finfo->nargs == 0)
9491                 appendPQExpBufferStr(&fn, "(*)");
9492         else
9493                 appendPQExpBuffer(&fn, "(%s)", funcargs);
9494         return fn.data;
9495 }
9496
9497 /*
9498  * format_function_arguments_old: generate function name and argument list
9499  *
9500  * The argument type names are qualified if needed.  The function name
9501  * is never qualified.
9502  *
9503  * This is used only with pre-8.4 servers, so we aren't expecting to see
9504  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9505  *
9506  * Any or all of allargtypes, argmodes, argnames may be NULL.
9507  */
9508 static char *
9509 format_function_arguments_old(Archive *fout,
9510                                                           FuncInfo *finfo, int nallargs,
9511                                                           char **allargtypes,
9512                                                           char **argmodes,
9513                                                           char **argnames)
9514 {
9515         PQExpBufferData fn;
9516         int                     j;
9517
9518         initPQExpBuffer(&fn);
9519         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9520         for (j = 0; j < nallargs; j++)
9521         {
9522                 Oid                     typid;
9523                 char       *typname;
9524                 const char *argmode;
9525                 const char *argname;
9526
9527                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9528                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9529
9530                 if (argmodes)
9531                 {
9532                         switch (argmodes[j][0])
9533                         {
9534                                 case PROARGMODE_IN:
9535                                         argmode = "";
9536                                         break;
9537                                 case PROARGMODE_OUT:
9538                                         argmode = "OUT ";
9539                                         break;
9540                                 case PROARGMODE_INOUT:
9541                                         argmode = "INOUT ";
9542                                         break;
9543                                 default:
9544                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9545                                         argmode = "";
9546                                         break;
9547                         }
9548                 }
9549                 else
9550                         argmode = "";
9551
9552                 argname = argnames ? argnames[j] : (char *) NULL;
9553                 if (argname && argname[0] == '\0')
9554                         argname = NULL;
9555
9556                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9557                                                   (j > 0) ? ", " : "",
9558                                                   argmode,
9559                                                   argname ? fmtId(argname) : "",
9560                                                   argname ? " " : "",
9561                                                   typname);
9562                 free(typname);
9563         }
9564         appendPQExpBufferChar(&fn, ')');
9565         return fn.data;
9566 }
9567
9568 /*
9569  * format_function_signature: generate function name and argument list
9570  *
9571  * This is like format_function_arguments_old except that only a minimal
9572  * list of input argument types is generated; this is sufficient to
9573  * reference the function, but not to define it.
9574  *
9575  * If honor_quotes is false then the function name is never quoted.
9576  * This is appropriate for use in TOC tags, but not in SQL commands.
9577  */
9578 static char *
9579 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9580 {
9581         PQExpBufferData fn;
9582         int                     j;
9583
9584         initPQExpBuffer(&fn);
9585         if (honor_quotes)
9586                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9587         else
9588                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9589         for (j = 0; j < finfo->nargs; j++)
9590         {
9591                 char       *typname;
9592
9593                 if (j > 0)
9594                         appendPQExpBufferStr(&fn, ", ");
9595
9596                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9597                                                                            zeroAsOpaque);
9598                 appendPQExpBufferStr(&fn, typname);
9599                 free(typname);
9600         }
9601         appendPQExpBufferChar(&fn, ')');
9602         return fn.data;
9603 }
9604
9605
9606 /*
9607  * dumpFunc:
9608  *        dump out one function
9609  */
9610 static void
9611 dumpFunc(Archive *fout, FuncInfo *finfo)
9612 {
9613         PQExpBuffer query;
9614         PQExpBuffer q;
9615         PQExpBuffer delqry;
9616         PQExpBuffer labelq;
9617         PQExpBuffer asPart;
9618         PGresult   *res;
9619         char       *funcsig;            /* identity signature */
9620         char       *funcfullsig = NULL; /* full signature */
9621         char       *funcsig_tag;
9622         char       *proretset;
9623         char       *prosrc;
9624         char       *probin;
9625         char       *funcargs;
9626         char       *funciargs;
9627         char       *funcresult;
9628         char       *proallargtypes;
9629         char       *proargmodes;
9630         char       *proargnames;
9631         char       *proiswindow;
9632         char       *provolatile;
9633         char       *proisstrict;
9634         char       *prosecdef;
9635         char       *proleakproof;
9636         char       *proconfig;
9637         char       *procost;
9638         char       *prorows;
9639         char       *lanname;
9640         char       *rettypename;
9641         int                     nallargs;
9642         char      **allargtypes = NULL;
9643         char      **argmodes = NULL;
9644         char      **argnames = NULL;
9645         char      **configitems = NULL;
9646         int                     nconfigitems = 0;
9647         int                     i;
9648
9649         /* Skip if not to be dumped */
9650         if (!finfo->dobj.dump || dataOnly)
9651                 return;
9652
9653         query = createPQExpBuffer();
9654         q = createPQExpBuffer();
9655         delqry = createPQExpBuffer();
9656         labelq = createPQExpBuffer();
9657         asPart = createPQExpBuffer();
9658
9659         /* Set proper schema search path so type references list correctly */
9660         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9661
9662         /* Fetch function-specific details */
9663         if (fout->remoteVersion >= 90200)
9664         {
9665                 /*
9666                  * proleakproof was added at v9.2
9667                  */
9668                 appendPQExpBuffer(query,
9669                                                   "SELECT proretset, prosrc, probin, "
9670                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9671                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9672                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9673                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9674                                                   "proleakproof, proconfig, procost, prorows, "
9675                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9676                                                   "FROM pg_catalog.pg_proc "
9677                                                   "WHERE oid = '%u'::pg_catalog.oid",
9678                                                   finfo->dobj.catId.oid);
9679         }
9680         else if (fout->remoteVersion >= 80400)
9681         {
9682                 /*
9683                  * In 8.4 and up we rely on pg_get_function_arguments and
9684                  * pg_get_function_result instead of examining proallargtypes etc.
9685                  */
9686                 appendPQExpBuffer(query,
9687                                                   "SELECT proretset, prosrc, probin, "
9688                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9689                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9690                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9691                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9692                                                   "false AS proleakproof, "
9693                                                   " proconfig, procost, prorows, "
9694                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9695                                                   "FROM pg_catalog.pg_proc "
9696                                                   "WHERE oid = '%u'::pg_catalog.oid",
9697                                                   finfo->dobj.catId.oid);
9698         }
9699         else if (fout->remoteVersion >= 80300)
9700         {
9701                 appendPQExpBuffer(query,
9702                                                   "SELECT proretset, prosrc, probin, "
9703                                                   "proallargtypes, proargmodes, proargnames, "
9704                                                   "false AS proiswindow, "
9705                                                   "provolatile, proisstrict, prosecdef, "
9706                                                   "false AS proleakproof, "
9707                                                   "proconfig, procost, prorows, "
9708                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9709                                                   "FROM pg_catalog.pg_proc "
9710                                                   "WHERE oid = '%u'::pg_catalog.oid",
9711                                                   finfo->dobj.catId.oid);
9712         }
9713         else if (fout->remoteVersion >= 80100)
9714         {
9715                 appendPQExpBuffer(query,
9716                                                   "SELECT proretset, prosrc, probin, "
9717                                                   "proallargtypes, proargmodes, proargnames, "
9718                                                   "false AS proiswindow, "
9719                                                   "provolatile, proisstrict, prosecdef, "
9720                                                   "false AS proleakproof, "
9721                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9722                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9723                                                   "FROM pg_catalog.pg_proc "
9724                                                   "WHERE oid = '%u'::pg_catalog.oid",
9725                                                   finfo->dobj.catId.oid);
9726         }
9727         else if (fout->remoteVersion >= 80000)
9728         {
9729                 appendPQExpBuffer(query,
9730                                                   "SELECT proretset, prosrc, probin, "
9731                                                   "null AS proallargtypes, "
9732                                                   "null AS proargmodes, "
9733                                                   "proargnames, "
9734                                                   "false AS proiswindow, "
9735                                                   "provolatile, proisstrict, prosecdef, "
9736                                                   "false AS proleakproof, "
9737                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9738                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9739                                                   "FROM pg_catalog.pg_proc "
9740                                                   "WHERE oid = '%u'::pg_catalog.oid",
9741                                                   finfo->dobj.catId.oid);
9742         }
9743         else if (fout->remoteVersion >= 70300)
9744         {
9745                 appendPQExpBuffer(query,
9746                                                   "SELECT proretset, prosrc, probin, "
9747                                                   "null AS proallargtypes, "
9748                                                   "null AS proargmodes, "
9749                                                   "null AS proargnames, "
9750                                                   "false AS proiswindow, "
9751                                                   "provolatile, proisstrict, prosecdef, "
9752                                                   "false AS proleakproof, "
9753                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9754                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9755                                                   "FROM pg_catalog.pg_proc "
9756                                                   "WHERE oid = '%u'::pg_catalog.oid",
9757                                                   finfo->dobj.catId.oid);
9758         }
9759         else if (fout->remoteVersion >= 70100)
9760         {
9761                 appendPQExpBuffer(query,
9762                                                   "SELECT proretset, prosrc, probin, "
9763                                                   "null AS proallargtypes, "
9764                                                   "null AS proargmodes, "
9765                                                   "null AS proargnames, "
9766                                                   "false AS proiswindow, "
9767                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9768                                                   "proisstrict, "
9769                                                   "false AS prosecdef, "
9770                                                   "false AS proleakproof, "
9771                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9772                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9773                                                   "FROM pg_proc "
9774                                                   "WHERE oid = '%u'::oid",
9775                                                   finfo->dobj.catId.oid);
9776         }
9777         else
9778         {
9779                 appendPQExpBuffer(query,
9780                                                   "SELECT proretset, prosrc, probin, "
9781                                                   "null AS proallargtypes, "
9782                                                   "null AS proargmodes, "
9783                                                   "null AS proargnames, "
9784                                                   "false AS proiswindow, "
9785                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9786                                                   "false AS proisstrict, "
9787                                                   "false AS prosecdef, "
9788                                                   "false AS proleakproof, "
9789                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9790                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9791                                                   "FROM pg_proc "
9792                                                   "WHERE oid = '%u'::oid",
9793                                                   finfo->dobj.catId.oid);
9794         }
9795
9796         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9797
9798         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9799         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9800         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9801         if (fout->remoteVersion >= 80400)
9802         {
9803                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9804                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9805                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9806                 proallargtypes = proargmodes = proargnames = NULL;
9807         }
9808         else
9809         {
9810                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9811                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9812                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9813                 funcargs = funciargs = funcresult = NULL;
9814         }
9815         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9816         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9817         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9818         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9819         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9820         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9821         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9822         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9823         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9824
9825         /*
9826          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9827          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9828          * versions would set it to "-".  There are no known cases in which prosrc
9829          * is unused, so the tests below for "-" are probably useless.
9830          */
9831         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9832         {
9833                 appendPQExpBufferStr(asPart, "AS ");
9834                 appendStringLiteralAH(asPart, probin, fout);
9835                 if (strcmp(prosrc, "-") != 0)
9836                 {
9837                         appendPQExpBufferStr(asPart, ", ");
9838
9839                         /*
9840                          * where we have bin, use dollar quoting if allowed and src
9841                          * contains quote or backslash; else use regular quoting.
9842                          */
9843                         if (disable_dollar_quoting ||
9844                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9845                                 appendStringLiteralAH(asPart, prosrc, fout);
9846                         else
9847                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9848                 }
9849         }
9850         else
9851         {
9852                 if (strcmp(prosrc, "-") != 0)
9853                 {
9854                         appendPQExpBufferStr(asPart, "AS ");
9855                         /* with no bin, dollar quote src unconditionally if allowed */
9856                         if (disable_dollar_quoting)
9857                                 appendStringLiteralAH(asPart, prosrc, fout);
9858                         else
9859                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9860                 }
9861         }
9862
9863         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9864
9865         if (proallargtypes && *proallargtypes)
9866         {
9867                 int                     nitems = 0;
9868
9869                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9870                         nitems < finfo->nargs)
9871                 {
9872                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9873                         if (allargtypes)
9874                                 free(allargtypes);
9875                         allargtypes = NULL;
9876                 }
9877                 else
9878                         nallargs = nitems;
9879         }
9880
9881         if (proargmodes && *proargmodes)
9882         {
9883                 int                     nitems = 0;
9884
9885                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9886                         nitems != nallargs)
9887                 {
9888                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9889                         if (argmodes)
9890                                 free(argmodes);
9891                         argmodes = NULL;
9892                 }
9893         }
9894
9895         if (proargnames && *proargnames)
9896         {
9897                 int                     nitems = 0;
9898
9899                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9900                         nitems != nallargs)
9901                 {
9902                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9903                         if (argnames)
9904                                 free(argnames);
9905                         argnames = NULL;
9906                 }
9907         }
9908
9909         if (proconfig && *proconfig)
9910         {
9911                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9912                 {
9913                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9914                         if (configitems)
9915                                 free(configitems);
9916                         configitems = NULL;
9917                         nconfigitems = 0;
9918                 }
9919         }
9920
9921         if (funcargs)
9922         {
9923                 /* 8.4 or later; we rely on server-side code for most of the work */
9924                 funcfullsig = format_function_arguments(finfo, funcargs, false);
9925                 funcsig = format_function_arguments(finfo, funciargs, false);
9926         }
9927         else
9928                 /* pre-8.4, do it ourselves */
9929                 funcsig = format_function_arguments_old(fout,
9930                                                                                                 finfo, nallargs, allargtypes,
9931                                                                                                 argmodes, argnames);
9932
9933         funcsig_tag = format_function_signature(fout, finfo, false);
9934
9935         /*
9936          * DROP must be fully qualified in case same name appears in pg_catalog
9937          */
9938         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9939                                           fmtId(finfo->dobj.namespace->dobj.name),
9940                                           funcsig);
9941
9942         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig :
9943                                           funcsig);
9944         if (funcresult)
9945                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9946         else
9947         {
9948                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9949                                                                                    zeroAsOpaque);
9950                 appendPQExpBuffer(q, "RETURNS %s%s",
9951                                                   (proretset[0] == 't') ? "SETOF " : "",
9952                                                   rettypename);
9953                 free(rettypename);
9954         }
9955
9956         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9957
9958         if (proiswindow[0] == 't')
9959                 appendPQExpBufferStr(q, " WINDOW");
9960
9961         if (provolatile[0] != PROVOLATILE_VOLATILE)
9962         {
9963                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9964                         appendPQExpBufferStr(q, " IMMUTABLE");
9965                 else if (provolatile[0] == PROVOLATILE_STABLE)
9966                         appendPQExpBufferStr(q, " STABLE");
9967                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9968                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9969                                                   finfo->dobj.name);
9970         }
9971
9972         if (proisstrict[0] == 't')
9973                 appendPQExpBufferStr(q, " STRICT");
9974
9975         if (prosecdef[0] == 't')
9976                 appendPQExpBufferStr(q, " SECURITY DEFINER");
9977
9978         if (proleakproof[0] == 't')
9979                 appendPQExpBufferStr(q, " LEAKPROOF");
9980
9981         /*
9982          * COST and ROWS are emitted only if present and not default, so as not to
9983          * break backwards-compatibility of the dump without need.      Keep this code
9984          * in sync with the defaults in functioncmds.c.
9985          */
9986         if (strcmp(procost, "0") != 0)
9987         {
9988                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9989                 {
9990                         /* default cost is 1 */
9991                         if (strcmp(procost, "1") != 0)
9992                                 appendPQExpBuffer(q, " COST %s", procost);
9993                 }
9994                 else
9995                 {
9996                         /* default cost is 100 */
9997                         if (strcmp(procost, "100") != 0)
9998                                 appendPQExpBuffer(q, " COST %s", procost);
9999                 }
10000         }
10001         if (proretset[0] == 't' &&
10002                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
10003                 appendPQExpBuffer(q, " ROWS %s", prorows);
10004
10005         for (i = 0; i < nconfigitems; i++)
10006         {
10007                 /* we feel free to scribble on configitems[] here */
10008                 char       *configitem = configitems[i];
10009                 char       *pos;
10010
10011                 pos = strchr(configitem, '=');
10012                 if (pos == NULL)
10013                         continue;
10014                 *pos++ = '\0';
10015                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
10016
10017                 /*
10018                  * Some GUC variable names are 'LIST' type and hence must not be
10019                  * quoted.
10020                  */
10021                 if (pg_strcasecmp(configitem, "DateStyle") == 0
10022                         || pg_strcasecmp(configitem, "search_path") == 0)
10023                         appendPQExpBufferStr(q, pos);
10024                 else
10025                         appendStringLiteralAH(q, pos, fout);
10026         }
10027
10028         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
10029
10030         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
10031
10032         if (binary_upgrade)
10033                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
10034
10035         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
10036                                  funcsig_tag,
10037                                  finfo->dobj.namespace->dobj.name,
10038                                  NULL,
10039                                  finfo->rolname, false,
10040                                  "FUNCTION", SECTION_PRE_DATA,
10041                                  q->data, delqry->data, NULL,
10042                                  NULL, 0,
10043                                  NULL, NULL);
10044
10045         /* Dump Function Comments and Security Labels */
10046         dumpComment(fout, labelq->data,
10047                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
10048                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
10049         dumpSecLabel(fout, labelq->data,
10050                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
10051                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
10052
10053         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
10054                         funcsig, NULL, funcsig_tag,
10055                         finfo->dobj.namespace->dobj.name,
10056                         finfo->rolname, finfo->proacl);
10057
10058         PQclear(res);
10059
10060         destroyPQExpBuffer(query);
10061         destroyPQExpBuffer(q);
10062         destroyPQExpBuffer(delqry);
10063         destroyPQExpBuffer(labelq);
10064         destroyPQExpBuffer(asPart);
10065         free(funcsig);
10066         if (funcfullsig)
10067                 free(funcfullsig);
10068         free(funcsig_tag);
10069         if (allargtypes)
10070                 free(allargtypes);
10071         if (argmodes)
10072                 free(argmodes);
10073         if (argnames)
10074                 free(argnames);
10075         if (configitems)
10076                 free(configitems);
10077 }
10078
10079
10080 /*
10081  * Dump a user-defined cast
10082  */
10083 static void
10084 dumpCast(Archive *fout, CastInfo *cast)
10085 {
10086         PQExpBuffer defqry;
10087         PQExpBuffer delqry;
10088         PQExpBuffer labelq;
10089         FuncInfo   *funcInfo = NULL;
10090
10091         /* Skip if not to be dumped */
10092         if (!cast->dobj.dump || dataOnly)
10093                 return;
10094
10095         /* Cannot dump if we don't have the cast function's info */
10096         if (OidIsValid(cast->castfunc))
10097         {
10098                 funcInfo = findFuncByOid(cast->castfunc);
10099                 if (funcInfo == NULL)
10100                         return;
10101         }
10102
10103         /*
10104          * As per discussion we dump casts if one or more of the underlying
10105          * objects (the conversion function and the two data types) are not
10106          * builtin AND if all of the non-builtin objects are included in the dump.
10107          * Builtin meaning, the namespace name does not start with "pg_".
10108          *
10109          * However, for a cast that belongs to an extension, we must not use this
10110          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
10111          */
10112         if (!cast->dobj.ext_member)
10113         {
10114                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
10115                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
10116
10117                 if (sourceInfo == NULL || targetInfo == NULL)
10118                         return;
10119
10120                 /*
10121                  * Skip this cast if all objects are from pg_
10122                  */
10123                 if ((funcInfo == NULL ||
10124                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
10125                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10126                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10127                         return;
10128
10129                 /*
10130                  * Skip cast if function isn't from pg_ and is not to be dumped.
10131                  */
10132                 if (funcInfo &&
10133                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10134                         !funcInfo->dobj.dump)
10135                         return;
10136
10137                 /*
10138                  * Same for the source type
10139                  */
10140                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10141                         !sourceInfo->dobj.dump)
10142                         return;
10143
10144                 /*
10145                  * and the target type.
10146                  */
10147                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10148                         !targetInfo->dobj.dump)
10149                         return;
10150         }
10151
10152         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10153         selectSourceSchema(fout, "pg_catalog");
10154
10155         defqry = createPQExpBuffer();
10156         delqry = createPQExpBuffer();
10157         labelq = createPQExpBuffer();
10158
10159         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10160                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10161                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10162
10163         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10164                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10165                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10166
10167         switch (cast->castmethod)
10168         {
10169                 case COERCION_METHOD_BINARY:
10170                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
10171                         break;
10172                 case COERCION_METHOD_INOUT:
10173                         appendPQExpBufferStr(defqry, "WITH INOUT");
10174                         break;
10175                 case COERCION_METHOD_FUNCTION:
10176                         if (funcInfo)
10177                         {
10178                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10179
10180                                 /*
10181                                  * Always qualify the function name, in case it is not in
10182                                  * pg_catalog schema (format_function_signature won't qualify
10183                                  * it).
10184                                  */
10185                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10186                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10187                                 free(fsig);
10188                         }
10189                         else
10190                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10191                         break;
10192                 default:
10193                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10194         }
10195
10196         if (cast->castcontext == 'a')
10197                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
10198         else if (cast->castcontext == 'i')
10199                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
10200         appendPQExpBufferStr(defqry, ";\n");
10201
10202         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10203                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10204                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10205
10206         if (binary_upgrade)
10207                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10208
10209         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10210                                  labelq->data,
10211                                  "pg_catalog", NULL, "",
10212                                  false, "CAST", SECTION_PRE_DATA,
10213                                  defqry->data, delqry->data, NULL,
10214                                  NULL, 0,
10215                                  NULL, NULL);
10216
10217         /* Dump Cast Comments */
10218         dumpComment(fout, labelq->data,
10219                                 NULL, "",
10220                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10221
10222         destroyPQExpBuffer(defqry);
10223         destroyPQExpBuffer(delqry);
10224         destroyPQExpBuffer(labelq);
10225 }
10226
10227 /*
10228  * dumpOpr
10229  *        write out a single operator definition
10230  */
10231 static void
10232 dumpOpr(Archive *fout, OprInfo *oprinfo)
10233 {
10234         PQExpBuffer query;
10235         PQExpBuffer q;
10236         PQExpBuffer delq;
10237         PQExpBuffer labelq;
10238         PQExpBuffer oprid;
10239         PQExpBuffer details;
10240         const char *name;
10241         PGresult   *res;
10242         int                     i_oprkind;
10243         int                     i_oprcode;
10244         int                     i_oprleft;
10245         int                     i_oprright;
10246         int                     i_oprcom;
10247         int                     i_oprnegate;
10248         int                     i_oprrest;
10249         int                     i_oprjoin;
10250         int                     i_oprcanmerge;
10251         int                     i_oprcanhash;
10252         char       *oprkind;
10253         char       *oprcode;
10254         char       *oprleft;
10255         char       *oprright;
10256         char       *oprcom;
10257         char       *oprnegate;
10258         char       *oprrest;
10259         char       *oprjoin;
10260         char       *oprcanmerge;
10261         char       *oprcanhash;
10262         char       *oprregproc;
10263         char       *oprref;
10264
10265         /* Skip if not to be dumped */
10266         if (!oprinfo->dobj.dump || dataOnly)
10267                 return;
10268
10269         /*
10270          * some operators are invalid because they were the result of user
10271          * defining operators before commutators exist
10272          */
10273         if (!OidIsValid(oprinfo->oprcode))
10274                 return;
10275
10276         query = createPQExpBuffer();
10277         q = createPQExpBuffer();
10278         delq = createPQExpBuffer();
10279         labelq = createPQExpBuffer();
10280         oprid = createPQExpBuffer();
10281         details = createPQExpBuffer();
10282
10283         /* Make sure we are in proper schema so regoperator works correctly */
10284         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10285
10286         if (fout->remoteVersion >= 80300)
10287         {
10288                 appendPQExpBuffer(query, "SELECT oprkind, "
10289                                                   "oprcode::pg_catalog.regprocedure, "
10290                                                   "oprleft::pg_catalog.regtype, "
10291                                                   "oprright::pg_catalog.regtype, "
10292                                                   "oprcom::pg_catalog.regoperator, "
10293                                                   "oprnegate::pg_catalog.regoperator, "
10294                                                   "oprrest::pg_catalog.regprocedure, "
10295                                                   "oprjoin::pg_catalog.regprocedure, "
10296                                                   "oprcanmerge, oprcanhash "
10297                                                   "FROM pg_catalog.pg_operator "
10298                                                   "WHERE oid = '%u'::pg_catalog.oid",
10299                                                   oprinfo->dobj.catId.oid);
10300         }
10301         else if (fout->remoteVersion >= 70300)
10302         {
10303                 appendPQExpBuffer(query, "SELECT oprkind, "
10304                                                   "oprcode::pg_catalog.regprocedure, "
10305                                                   "oprleft::pg_catalog.regtype, "
10306                                                   "oprright::pg_catalog.regtype, "
10307                                                   "oprcom::pg_catalog.regoperator, "
10308                                                   "oprnegate::pg_catalog.regoperator, "
10309                                                   "oprrest::pg_catalog.regprocedure, "
10310                                                   "oprjoin::pg_catalog.regprocedure, "
10311                                                   "(oprlsortop != 0) AS oprcanmerge, "
10312                                                   "oprcanhash "
10313                                                   "FROM pg_catalog.pg_operator "
10314                                                   "WHERE oid = '%u'::pg_catalog.oid",
10315                                                   oprinfo->dobj.catId.oid);
10316         }
10317         else if (fout->remoteVersion >= 70100)
10318         {
10319                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10320                                                   "CASE WHEN oprleft = 0 THEN '-' "
10321                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10322                                                   "CASE WHEN oprright = 0 THEN '-' "
10323                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10324                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10325                                                   "(oprlsortop != 0) AS oprcanmerge, "
10326                                                   "oprcanhash "
10327                                                   "FROM pg_operator "
10328                                                   "WHERE oid = '%u'::oid",
10329                                                   oprinfo->dobj.catId.oid);
10330         }
10331         else
10332         {
10333                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10334                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10335                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10336                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10337                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10338                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10339                                                   "(oprlsortop != 0) AS oprcanmerge, "
10340                                                   "oprcanhash "
10341                                                   "FROM pg_operator "
10342                                                   "WHERE oid = '%u'::oid",
10343                                                   oprinfo->dobj.catId.oid);
10344         }
10345
10346         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10347
10348         i_oprkind = PQfnumber(res, "oprkind");
10349         i_oprcode = PQfnumber(res, "oprcode");
10350         i_oprleft = PQfnumber(res, "oprleft");
10351         i_oprright = PQfnumber(res, "oprright");
10352         i_oprcom = PQfnumber(res, "oprcom");
10353         i_oprnegate = PQfnumber(res, "oprnegate");
10354         i_oprrest = PQfnumber(res, "oprrest");
10355         i_oprjoin = PQfnumber(res, "oprjoin");
10356         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10357         i_oprcanhash = PQfnumber(res, "oprcanhash");
10358
10359         oprkind = PQgetvalue(res, 0, i_oprkind);
10360         oprcode = PQgetvalue(res, 0, i_oprcode);
10361         oprleft = PQgetvalue(res, 0, i_oprleft);
10362         oprright = PQgetvalue(res, 0, i_oprright);
10363         oprcom = PQgetvalue(res, 0, i_oprcom);
10364         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10365         oprrest = PQgetvalue(res, 0, i_oprrest);
10366         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10367         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10368         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10369
10370         oprregproc = convertRegProcReference(fout, oprcode);
10371         if (oprregproc)
10372         {
10373                 appendPQExpBuffer(details, "    PROCEDURE = %s", oprregproc);
10374                 free(oprregproc);
10375         }
10376
10377         appendPQExpBuffer(oprid, "%s (",
10378                                           oprinfo->dobj.name);
10379
10380         /*
10381          * right unary means there's a left arg and left unary means there's a
10382          * right arg
10383          */
10384         if (strcmp(oprkind, "r") == 0 ||
10385                 strcmp(oprkind, "b") == 0)
10386         {
10387                 if (fout->remoteVersion >= 70100)
10388                         name = oprleft;
10389                 else
10390                         name = fmtId(oprleft);
10391                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10392                 appendPQExpBufferStr(oprid, name);
10393         }
10394         else
10395                 appendPQExpBufferStr(oprid, "NONE");
10396
10397         if (strcmp(oprkind, "l") == 0 ||
10398                 strcmp(oprkind, "b") == 0)
10399         {
10400                 if (fout->remoteVersion >= 70100)
10401                         name = oprright;
10402                 else
10403                         name = fmtId(oprright);
10404                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10405                 appendPQExpBuffer(oprid, ", %s)", name);
10406         }
10407         else
10408                 appendPQExpBufferStr(oprid, ", NONE)");
10409
10410         oprref = convertOperatorReference(fout, oprcom);
10411         if (oprref)
10412         {
10413                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
10414                 free(oprref);
10415         }
10416
10417         oprref = convertOperatorReference(fout, oprnegate);
10418         if (oprref)
10419         {
10420                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
10421                 free(oprref);
10422         }
10423
10424         if (strcmp(oprcanmerge, "t") == 0)
10425                 appendPQExpBufferStr(details, ",\n    MERGES");
10426
10427         if (strcmp(oprcanhash, "t") == 0)
10428                 appendPQExpBufferStr(details, ",\n    HASHES");
10429
10430         oprregproc = convertRegProcReference(fout, oprrest);
10431         if (oprregproc)
10432         {
10433                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
10434                 free(oprregproc);
10435         }
10436
10437         oprregproc = convertRegProcReference(fout, oprjoin);
10438         if (oprregproc)
10439         {
10440                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
10441                 free(oprregproc);
10442         }
10443
10444         /*
10445          * DROP must be fully qualified in case same name appears in pg_catalog
10446          */
10447         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10448                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10449                                           oprid->data);
10450
10451         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10452                                           oprinfo->dobj.name, details->data);
10453
10454         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10455
10456         if (binary_upgrade)
10457                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10458
10459         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10460                                  oprinfo->dobj.name,
10461                                  oprinfo->dobj.namespace->dobj.name,
10462                                  NULL,
10463                                  oprinfo->rolname,
10464                                  false, "OPERATOR", SECTION_PRE_DATA,
10465                                  q->data, delq->data, NULL,
10466                                  NULL, 0,
10467                                  NULL, NULL);
10468
10469         /* Dump Operator Comments */
10470         dumpComment(fout, labelq->data,
10471                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10472                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10473
10474         PQclear(res);
10475
10476         destroyPQExpBuffer(query);
10477         destroyPQExpBuffer(q);
10478         destroyPQExpBuffer(delq);
10479         destroyPQExpBuffer(labelq);
10480         destroyPQExpBuffer(oprid);
10481         destroyPQExpBuffer(details);
10482 }
10483
10484 /*
10485  * Convert a function reference obtained from pg_operator
10486  *
10487  * Returns allocated string of what to print, or NULL if function references
10488  * is InvalidOid. Returned string is expected to be free'd by the caller.
10489  *
10490  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10491  * argument-types part.  In prior versions, the input is a REGPROC display.
10492  */
10493 static char *
10494 convertRegProcReference(Archive *fout, const char *proc)
10495 {
10496         /* In all cases "-" means a null reference */
10497         if (strcmp(proc, "-") == 0)
10498                 return NULL;
10499
10500         if (fout->remoteVersion >= 70300)
10501         {
10502                 char       *name;
10503                 char       *paren;
10504                 bool            inquote;
10505
10506                 name = pg_strdup(proc);
10507                 /* find non-double-quoted left paren */
10508                 inquote = false;
10509                 for (paren = name; *paren; paren++)
10510                 {
10511                         if (*paren == '(' && !inquote)
10512                         {
10513                                 *paren = '\0';
10514                                 break;
10515                         }
10516                         if (*paren == '"')
10517                                 inquote = !inquote;
10518                 }
10519                 return name;
10520         }
10521
10522         /* REGPROC before 7.3 does not quote its result */
10523         return pg_strdup(fmtId(proc));
10524 }
10525
10526 /*
10527  * Convert an operator cross-reference obtained from pg_operator
10528  *
10529  * Returns an allocated string of what to print, or NULL to print nothing.
10530  * Caller is responsible for free'ing result string.
10531  *
10532  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10533  * argument-types part, and add OPERATOR() decoration if the name is
10534  * schema-qualified.  In older versions, the input is just a numeric OID,
10535  * which we search our operator list for.
10536  */
10537 static char *
10538 convertOperatorReference(Archive *fout, const char *opr)
10539 {
10540         OprInfo    *oprInfo;
10541
10542         /* In all cases "0" means a null reference */
10543         if (strcmp(opr, "0") == 0)
10544                 return NULL;
10545
10546         if (fout->remoteVersion >= 70300)
10547         {
10548                 char       *name;
10549                 char       *oname;
10550                 char       *ptr;
10551                 bool            inquote;
10552                 bool            sawdot;
10553
10554                 name = pg_strdup(opr);
10555                 /* find non-double-quoted left paren, and check for non-quoted dot */
10556                 inquote = false;
10557                 sawdot = false;
10558                 for (ptr = name; *ptr; ptr++)
10559                 {
10560                         if (*ptr == '"')
10561                                 inquote = !inquote;
10562                         else if (*ptr == '.' && !inquote)
10563                                 sawdot = true;
10564                         else if (*ptr == '(' && !inquote)
10565                         {
10566                                 *ptr = '\0';
10567                                 break;
10568                         }
10569                 }
10570                 /* If not schema-qualified, don't need to add OPERATOR() */
10571                 if (!sawdot)
10572                         return name;
10573                 oname = psprintf("OPERATOR(%s)", name);
10574                 free(name);
10575                 return oname;
10576         }
10577
10578         oprInfo = findOprByOid(atooid(opr));
10579         if (oprInfo == NULL)
10580         {
10581                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10582                                   opr);
10583                 return NULL;
10584         }
10585         return pg_strdup(oprInfo->dobj.name);
10586 }
10587
10588 /*
10589  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10590  *
10591  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10592  * argument lists of these functions are predetermined.  Note that the
10593  * caller should ensure we are in the proper schema, because the results
10594  * are search path dependent!
10595  */
10596 static const char *
10597 convertTSFunction(Archive *fout, Oid funcOid)
10598 {
10599         char       *result;
10600         char            query[128];
10601         PGresult   *res;
10602
10603         snprintf(query, sizeof(query),
10604                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10605         res = ExecuteSqlQueryForSingleRow(fout, query);
10606
10607         result = pg_strdup(PQgetvalue(res, 0, 0));
10608
10609         PQclear(res);
10610
10611         return result;
10612 }
10613
10614
10615 /*
10616  * dumpOpclass
10617  *        write out a single operator class definition
10618  */
10619 static void
10620 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10621 {
10622         PQExpBuffer query;
10623         PQExpBuffer q;
10624         PQExpBuffer delq;
10625         PQExpBuffer labelq;
10626         PGresult   *res;
10627         int                     ntups;
10628         int                     i_opcintype;
10629         int                     i_opckeytype;
10630         int                     i_opcdefault;
10631         int                     i_opcfamily;
10632         int                     i_opcfamilyname;
10633         int                     i_opcfamilynsp;
10634         int                     i_amname;
10635         int                     i_amopstrategy;
10636         int                     i_amopreqcheck;
10637         int                     i_amopopr;
10638         int                     i_sortfamily;
10639         int                     i_sortfamilynsp;
10640         int                     i_amprocnum;
10641         int                     i_amproc;
10642         int                     i_amproclefttype;
10643         int                     i_amprocrighttype;
10644         char       *opcintype;
10645         char       *opckeytype;
10646         char       *opcdefault;
10647         char       *opcfamily;
10648         char       *opcfamilyname;
10649         char       *opcfamilynsp;
10650         char       *amname;
10651         char       *amopstrategy;
10652         char       *amopreqcheck;
10653         char       *amopopr;
10654         char       *sortfamily;
10655         char       *sortfamilynsp;
10656         char       *amprocnum;
10657         char       *amproc;
10658         char       *amproclefttype;
10659         char       *amprocrighttype;
10660         bool            needComma;
10661         int                     i;
10662
10663         /* Skip if not to be dumped */
10664         if (!opcinfo->dobj.dump || dataOnly)
10665                 return;
10666
10667         /*
10668          * XXX currently we do not implement dumping of operator classes from
10669          * pre-7.3 databases.  This could be done but it seems not worth the
10670          * trouble.
10671          */
10672         if (fout->remoteVersion < 70300)
10673                 return;
10674
10675         query = createPQExpBuffer();
10676         q = createPQExpBuffer();
10677         delq = createPQExpBuffer();
10678         labelq = createPQExpBuffer();
10679
10680         /* Make sure we are in proper schema so regoperator works correctly */
10681         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10682
10683         /* Get additional fields from the pg_opclass row */
10684         if (fout->remoteVersion >= 80300)
10685         {
10686                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10687                                                   "opckeytype::pg_catalog.regtype, "
10688                                                   "opcdefault, opcfamily, "
10689                                                   "opfname AS opcfamilyname, "
10690                                                   "nspname AS opcfamilynsp, "
10691                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10692                                                   "FROM pg_catalog.pg_opclass c "
10693                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10694                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10695                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10696                                                   opcinfo->dobj.catId.oid);
10697         }
10698         else
10699         {
10700                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10701                                                   "opckeytype::pg_catalog.regtype, "
10702                                                   "opcdefault, NULL AS opcfamily, "
10703                                                   "NULL AS opcfamilyname, "
10704                                                   "NULL AS opcfamilynsp, "
10705                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10706                                                   "FROM pg_catalog.pg_opclass "
10707                                                   "WHERE oid = '%u'::pg_catalog.oid",
10708                                                   opcinfo->dobj.catId.oid);
10709         }
10710
10711         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10712
10713         i_opcintype = PQfnumber(res, "opcintype");
10714         i_opckeytype = PQfnumber(res, "opckeytype");
10715         i_opcdefault = PQfnumber(res, "opcdefault");
10716         i_opcfamily = PQfnumber(res, "opcfamily");
10717         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10718         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10719         i_amname = PQfnumber(res, "amname");
10720
10721         opcintype = PQgetvalue(res, 0, i_opcintype);
10722         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10723         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10724         /* opcfamily will still be needed after we PQclear res */
10725         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10726         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10727         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10728         /* amname will still be needed after we PQclear res */
10729         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10730
10731         /*
10732          * DROP must be fully qualified in case same name appears in pg_catalog
10733          */
10734         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10735                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10736         appendPQExpBuffer(delq, ".%s",
10737                                           fmtId(opcinfo->dobj.name));
10738         appendPQExpBuffer(delq, " USING %s;\n",
10739                                           fmtId(amname));
10740
10741         /* Build the fixed portion of the CREATE command */
10742         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10743                                           fmtId(opcinfo->dobj.name));
10744         if (strcmp(opcdefault, "t") == 0)
10745                 appendPQExpBufferStr(q, "DEFAULT ");
10746         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10747                                           opcintype,
10748                                           fmtId(amname));
10749         if (strlen(opcfamilyname) > 0 &&
10750                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10751                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10752         {
10753                 appendPQExpBufferStr(q, " FAMILY ");
10754                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10755                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10756                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10757         }
10758         appendPQExpBufferStr(q, " AS\n    ");
10759
10760         needComma = false;
10761
10762         if (strcmp(opckeytype, "-") != 0)
10763         {
10764                 appendPQExpBuffer(q, "STORAGE %s",
10765                                                   opckeytype);
10766                 needComma = true;
10767         }
10768
10769         PQclear(res);
10770
10771         /*
10772          * Now fetch and print the OPERATOR entries (pg_amop rows).
10773          *
10774          * Print only those opfamily members that are tied to the opclass by
10775          * pg_depend entries.
10776          *
10777          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10778          * older server's opclass in which it is used.  This is to avoid
10779          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10780          * older server and then reload into that old version.  This can go away
10781          * once 8.3 is so old as to not be of interest to anyone.
10782          */
10783         resetPQExpBuffer(query);
10784
10785         if (fout->remoteVersion >= 90100)
10786         {
10787                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10788                                                   "amopopr::pg_catalog.regoperator, "
10789                                                   "opfname AS sortfamily, "
10790                                                   "nspname AS sortfamilynsp "
10791                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10792                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10793                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10794                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10795                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10796                                                   "AND refobjid = '%u'::pg_catalog.oid "
10797                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10798                                                   "ORDER BY amopstrategy",
10799                                                   opcinfo->dobj.catId.oid,
10800                                                   opcfamily);
10801         }
10802         else if (fout->remoteVersion >= 80400)
10803         {
10804                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10805                                                   "amopopr::pg_catalog.regoperator, "
10806                                                   "NULL AS sortfamily, "
10807                                                   "NULL AS sortfamilynsp "
10808                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10809                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10810                                                   "AND refobjid = '%u'::pg_catalog.oid "
10811                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10812                                                   "AND objid = ao.oid "
10813                                                   "ORDER BY amopstrategy",
10814                                                   opcinfo->dobj.catId.oid);
10815         }
10816         else if (fout->remoteVersion >= 80300)
10817         {
10818                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10819                                                   "amopopr::pg_catalog.regoperator, "
10820                                                   "NULL AS sortfamily, "
10821                                                   "NULL AS sortfamilynsp "
10822                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10823                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10824                                                   "AND refobjid = '%u'::pg_catalog.oid "
10825                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10826                                                   "AND objid = ao.oid "
10827                                                   "ORDER BY amopstrategy",
10828                                                   opcinfo->dobj.catId.oid);
10829         }
10830         else
10831         {
10832                 /*
10833                  * Here, we print all entries since there are no opfamilies and hence
10834                  * no loose operators to worry about.
10835                  */
10836                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10837                                                   "amopopr::pg_catalog.regoperator, "
10838                                                   "NULL AS sortfamily, "
10839                                                   "NULL AS sortfamilynsp "
10840                                                   "FROM pg_catalog.pg_amop "
10841                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10842                                                   "ORDER BY amopstrategy",
10843                                                   opcinfo->dobj.catId.oid);
10844         }
10845
10846         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10847
10848         ntups = PQntuples(res);
10849
10850         i_amopstrategy = PQfnumber(res, "amopstrategy");
10851         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10852         i_amopopr = PQfnumber(res, "amopopr");
10853         i_sortfamily = PQfnumber(res, "sortfamily");
10854         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10855
10856         for (i = 0; i < ntups; i++)
10857         {
10858                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10859                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10860                 amopopr = PQgetvalue(res, i, i_amopopr);
10861                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10862                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10863
10864                 if (needComma)
10865                         appendPQExpBufferStr(q, " ,\n    ");
10866
10867                 appendPQExpBuffer(q, "OPERATOR %s %s",
10868                                                   amopstrategy, amopopr);
10869
10870                 if (strlen(sortfamily) > 0)
10871                 {
10872                         appendPQExpBufferStr(q, " FOR ORDER BY ");
10873                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10874                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10875                         appendPQExpBufferStr(q, fmtId(sortfamily));
10876                 }
10877
10878                 if (strcmp(amopreqcheck, "t") == 0)
10879                         appendPQExpBufferStr(q, " RECHECK");
10880
10881                 needComma = true;
10882         }
10883
10884         PQclear(res);
10885
10886         /*
10887          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10888          *
10889          * Print only those opfamily members that are tied to the opclass by
10890          * pg_depend entries.
10891          *
10892          * We print the amproclefttype/amprocrighttype even though in most cases
10893          * the backend could deduce the right values, because of the corner case
10894          * of a btree sort support function for a cross-type comparison.  That's
10895          * only allowed in 9.2 and later, but for simplicity print them in all
10896          * versions that have the columns.
10897          */
10898         resetPQExpBuffer(query);
10899
10900         if (fout->remoteVersion >= 80300)
10901         {
10902                 appendPQExpBuffer(query, "SELECT amprocnum, "
10903                                                   "amproc::pg_catalog.regprocedure, "
10904                                                   "amproclefttype::pg_catalog.regtype, "
10905                                                   "amprocrighttype::pg_catalog.regtype "
10906                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10907                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10908                                                   "AND refobjid = '%u'::pg_catalog.oid "
10909                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10910                                                   "AND objid = ap.oid "
10911                                                   "ORDER BY amprocnum",
10912                                                   opcinfo->dobj.catId.oid);
10913         }
10914         else
10915         {
10916                 appendPQExpBuffer(query, "SELECT amprocnum, "
10917                                                   "amproc::pg_catalog.regprocedure, "
10918                                                   "'' AS amproclefttype, "
10919                                                   "'' AS amprocrighttype "
10920                                                   "FROM pg_catalog.pg_amproc "
10921                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10922                                                   "ORDER BY amprocnum",
10923                                                   opcinfo->dobj.catId.oid);
10924         }
10925
10926         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10927
10928         ntups = PQntuples(res);
10929
10930         i_amprocnum = PQfnumber(res, "amprocnum");
10931         i_amproc = PQfnumber(res, "amproc");
10932         i_amproclefttype = PQfnumber(res, "amproclefttype");
10933         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10934
10935         for (i = 0; i < ntups; i++)
10936         {
10937                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10938                 amproc = PQgetvalue(res, i, i_amproc);
10939                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10940                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10941
10942                 if (needComma)
10943                         appendPQExpBufferStr(q, " ,\n    ");
10944
10945                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10946
10947                 if (*amproclefttype && *amprocrighttype)
10948                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10949
10950                 appendPQExpBuffer(q, " %s", amproc);
10951
10952                 needComma = true;
10953         }
10954
10955         PQclear(res);
10956
10957         appendPQExpBufferStr(q, ";\n");
10958
10959         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10960                                           fmtId(opcinfo->dobj.name));
10961         appendPQExpBuffer(labelq, " USING %s",
10962                                           fmtId(amname));
10963
10964         if (binary_upgrade)
10965                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10966
10967         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10968                                  opcinfo->dobj.name,
10969                                  opcinfo->dobj.namespace->dobj.name,
10970                                  NULL,
10971                                  opcinfo->rolname,
10972                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10973                                  q->data, delq->data, NULL,
10974                                  NULL, 0,
10975                                  NULL, NULL);
10976
10977         /* Dump Operator Class Comments */
10978         dumpComment(fout, labelq->data,
10979                                 NULL, opcinfo->rolname,
10980                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10981
10982         free(amname);
10983         destroyPQExpBuffer(query);
10984         destroyPQExpBuffer(q);
10985         destroyPQExpBuffer(delq);
10986         destroyPQExpBuffer(labelq);
10987 }
10988
10989 /*
10990  * dumpOpfamily
10991  *        write out a single operator family definition
10992  *
10993  * Note: this also dumps any "loose" operator members that aren't bound to a
10994  * specific opclass within the opfamily.
10995  */
10996 static void
10997 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10998 {
10999         PQExpBuffer query;
11000         PQExpBuffer q;
11001         PQExpBuffer delq;
11002         PQExpBuffer labelq;
11003         PGresult   *res;
11004         PGresult   *res_ops;
11005         PGresult   *res_procs;
11006         int                     ntups;
11007         int                     i_amname;
11008         int                     i_amopstrategy;
11009         int                     i_amopreqcheck;
11010         int                     i_amopopr;
11011         int                     i_sortfamily;
11012         int                     i_sortfamilynsp;
11013         int                     i_amprocnum;
11014         int                     i_amproc;
11015         int                     i_amproclefttype;
11016         int                     i_amprocrighttype;
11017         char       *amname;
11018         char       *amopstrategy;
11019         char       *amopreqcheck;
11020         char       *amopopr;
11021         char       *sortfamily;
11022         char       *sortfamilynsp;
11023         char       *amprocnum;
11024         char       *amproc;
11025         char       *amproclefttype;
11026         char       *amprocrighttype;
11027         bool            needComma;
11028         int                     i;
11029
11030         /* Skip if not to be dumped */
11031         if (!opfinfo->dobj.dump || dataOnly)
11032                 return;
11033
11034         /*
11035          * We want to dump the opfamily only if (1) it contains "loose" operators
11036          * or functions, or (2) it contains an opclass with a different name or
11037          * owner.  Otherwise it's sufficient to let it be created during creation
11038          * of the contained opclass, and not dumping it improves portability of
11039          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
11040          * that first.
11041          */
11042
11043         query = createPQExpBuffer();
11044         q = createPQExpBuffer();
11045         delq = createPQExpBuffer();
11046         labelq = createPQExpBuffer();
11047
11048         /* Make sure we are in proper schema so regoperator works correctly */
11049         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
11050
11051         /*
11052          * Fetch only those opfamily members that are tied directly to the
11053          * opfamily by pg_depend entries.
11054          *
11055          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
11056          * older server's opclass in which it is used.  This is to avoid
11057          * hard-to-detect breakage if a newer pg_dump is used to dump from an
11058          * older server and then reload into that old version.  This can go away
11059          * once 8.3 is so old as to not be of interest to anyone.
11060          */
11061         if (fout->remoteVersion >= 90100)
11062         {
11063                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11064                                                   "amopopr::pg_catalog.regoperator, "
11065                                                   "opfname AS sortfamily, "
11066                                                   "nspname AS sortfamilynsp "
11067                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
11068                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
11069                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
11070                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
11071                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11072                                                   "AND refobjid = '%u'::pg_catalog.oid "
11073                                                   "AND amopfamily = '%u'::pg_catalog.oid "
11074                                                   "ORDER BY amopstrategy",
11075                                                   opfinfo->dobj.catId.oid,
11076                                                   opfinfo->dobj.catId.oid);
11077         }
11078         else if (fout->remoteVersion >= 80400)
11079         {
11080                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11081                                                   "amopopr::pg_catalog.regoperator, "
11082                                                   "NULL AS sortfamily, "
11083                                                   "NULL AS sortfamilynsp "
11084                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11085                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11086                                                   "AND refobjid = '%u'::pg_catalog.oid "
11087                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11088                                                   "AND objid = ao.oid "
11089                                                   "ORDER BY amopstrategy",
11090                                                   opfinfo->dobj.catId.oid);
11091         }
11092         else
11093         {
11094                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
11095                                                   "amopopr::pg_catalog.regoperator, "
11096                                                   "NULL AS sortfamily, "
11097                                                   "NULL AS sortfamilynsp "
11098                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11099                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11100                                                   "AND refobjid = '%u'::pg_catalog.oid "
11101                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11102                                                   "AND objid = ao.oid "
11103                                                   "ORDER BY amopstrategy",
11104                                                   opfinfo->dobj.catId.oid);
11105         }
11106
11107         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11108
11109         resetPQExpBuffer(query);
11110
11111         appendPQExpBuffer(query, "SELECT amprocnum, "
11112                                           "amproc::pg_catalog.regprocedure, "
11113                                           "amproclefttype::pg_catalog.regtype, "
11114                                           "amprocrighttype::pg_catalog.regtype "
11115                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
11116                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11117                                           "AND refobjid = '%u'::pg_catalog.oid "
11118                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
11119                                           "AND objid = ap.oid "
11120                                           "ORDER BY amprocnum",
11121                                           opfinfo->dobj.catId.oid);
11122
11123         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11124
11125         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
11126         {
11127                 /* No loose members, so check contained opclasses */
11128                 resetPQExpBuffer(query);
11129
11130                 appendPQExpBuffer(query, "SELECT 1 "
11131                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
11132                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
11133                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11134                                                   "AND refobjid = f.oid "
11135                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11136                                                   "AND objid = c.oid "
11137                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
11138                                                   "LIMIT 1",
11139                                                   opfinfo->dobj.catId.oid);
11140
11141                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11142
11143                 if (PQntuples(res) == 0)
11144                 {
11145                         /* no need to dump it, so bail out */
11146                         PQclear(res);
11147                         PQclear(res_ops);
11148                         PQclear(res_procs);
11149                         destroyPQExpBuffer(query);
11150                         destroyPQExpBuffer(q);
11151                         destroyPQExpBuffer(delq);
11152                         destroyPQExpBuffer(labelq);
11153                         return;
11154                 }
11155
11156                 PQclear(res);
11157         }
11158
11159         /* Get additional fields from the pg_opfamily row */
11160         resetPQExpBuffer(query);
11161
11162         appendPQExpBuffer(query, "SELECT "
11163          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11164                                           "FROM pg_catalog.pg_opfamily "
11165                                           "WHERE oid = '%u'::pg_catalog.oid",
11166                                           opfinfo->dobj.catId.oid);
11167
11168         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11169
11170         i_amname = PQfnumber(res, "amname");
11171
11172         /* amname will still be needed after we PQclear res */
11173         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11174
11175         /*
11176          * DROP must be fully qualified in case same name appears in pg_catalog
11177          */
11178         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11179                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11180         appendPQExpBuffer(delq, ".%s",
11181                                           fmtId(opfinfo->dobj.name));
11182         appendPQExpBuffer(delq, " USING %s;\n",
11183                                           fmtId(amname));
11184
11185         /* Build the fixed portion of the CREATE command */
11186         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11187                                           fmtId(opfinfo->dobj.name));
11188         appendPQExpBuffer(q, " USING %s;\n",
11189                                           fmtId(amname));
11190
11191         PQclear(res);
11192
11193         /* Do we need an ALTER to add loose members? */
11194         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11195         {
11196                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11197                                                   fmtId(opfinfo->dobj.name));
11198                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11199                                                   fmtId(amname));
11200
11201                 needComma = false;
11202
11203                 /*
11204                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11205                  */
11206                 ntups = PQntuples(res_ops);
11207
11208                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11209                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11210                 i_amopopr = PQfnumber(res_ops, "amopopr");
11211                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11212                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11213
11214                 for (i = 0; i < ntups; i++)
11215                 {
11216                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11217                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11218                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11219                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11220                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11221
11222                         if (needComma)
11223                                 appendPQExpBufferStr(q, " ,\n    ");
11224
11225                         appendPQExpBuffer(q, "OPERATOR %s %s",
11226                                                           amopstrategy, amopopr);
11227
11228                         if (strlen(sortfamily) > 0)
11229                         {
11230                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
11231                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11232                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11233                                 appendPQExpBufferStr(q, fmtId(sortfamily));
11234                         }
11235
11236                         if (strcmp(amopreqcheck, "t") == 0)
11237                                 appendPQExpBufferStr(q, " RECHECK");
11238
11239                         needComma = true;
11240                 }
11241
11242                 /*
11243                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11244                  */
11245                 ntups = PQntuples(res_procs);
11246
11247                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11248                 i_amproc = PQfnumber(res_procs, "amproc");
11249                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11250                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11251
11252                 for (i = 0; i < ntups; i++)
11253                 {
11254                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11255                         amproc = PQgetvalue(res_procs, i, i_amproc);
11256                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11257                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11258
11259                         if (needComma)
11260                                 appendPQExpBufferStr(q, " ,\n    ");
11261
11262                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11263                                                           amprocnum, amproclefttype, amprocrighttype,
11264                                                           amproc);
11265
11266                         needComma = true;
11267                 }
11268
11269                 appendPQExpBufferStr(q, ";\n");
11270         }
11271
11272         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11273                                           fmtId(opfinfo->dobj.name));
11274         appendPQExpBuffer(labelq, " USING %s",
11275                                           fmtId(amname));
11276
11277         if (binary_upgrade)
11278                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11279
11280         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11281                                  opfinfo->dobj.name,
11282                                  opfinfo->dobj.namespace->dobj.name,
11283                                  NULL,
11284                                  opfinfo->rolname,
11285                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11286                                  q->data, delq->data, NULL,
11287                                  NULL, 0,
11288                                  NULL, NULL);
11289
11290         /* Dump Operator Family Comments */
11291         dumpComment(fout, labelq->data,
11292                                 NULL, opfinfo->rolname,
11293                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11294
11295         free(amname);
11296         PQclear(res_ops);
11297         PQclear(res_procs);
11298         destroyPQExpBuffer(query);
11299         destroyPQExpBuffer(q);
11300         destroyPQExpBuffer(delq);
11301         destroyPQExpBuffer(labelq);
11302 }
11303
11304 /*
11305  * dumpCollation
11306  *        write out a single collation definition
11307  */
11308 static void
11309 dumpCollation(Archive *fout, CollInfo *collinfo)
11310 {
11311         PQExpBuffer query;
11312         PQExpBuffer q;
11313         PQExpBuffer delq;
11314         PQExpBuffer labelq;
11315         PGresult   *res;
11316         int                     i_collcollate;
11317         int                     i_collctype;
11318         const char *collcollate;
11319         const char *collctype;
11320
11321         /* Skip if not to be dumped */
11322         if (!collinfo->dobj.dump || dataOnly)
11323                 return;
11324
11325         query = createPQExpBuffer();
11326         q = createPQExpBuffer();
11327         delq = createPQExpBuffer();
11328         labelq = createPQExpBuffer();
11329
11330         /* Make sure we are in proper schema */
11331         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11332
11333         /* Get conversion-specific details */
11334         appendPQExpBuffer(query, "SELECT "
11335                                           "collcollate, "
11336                                           "collctype "
11337                                           "FROM pg_catalog.pg_collation c "
11338                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11339                                           collinfo->dobj.catId.oid);
11340
11341         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11342
11343         i_collcollate = PQfnumber(res, "collcollate");
11344         i_collctype = PQfnumber(res, "collctype");
11345
11346         collcollate = PQgetvalue(res, 0, i_collcollate);
11347         collctype = PQgetvalue(res, 0, i_collctype);
11348
11349         /*
11350          * DROP must be fully qualified in case same name appears in pg_catalog
11351          */
11352         appendPQExpBuffer(delq, "DROP COLLATION %s",
11353                                           fmtId(collinfo->dobj.namespace->dobj.name));
11354         appendPQExpBuffer(delq, ".%s;\n",
11355                                           fmtId(collinfo->dobj.name));
11356
11357         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11358                                           fmtId(collinfo->dobj.name));
11359         appendStringLiteralAH(q, collcollate, fout);
11360         appendPQExpBufferStr(q, ", lc_ctype = ");
11361         appendStringLiteralAH(q, collctype, fout);
11362         appendPQExpBufferStr(q, ");\n");
11363
11364         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11365
11366         if (binary_upgrade)
11367                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11368
11369         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11370                                  collinfo->dobj.name,
11371                                  collinfo->dobj.namespace->dobj.name,
11372                                  NULL,
11373                                  collinfo->rolname,
11374                                  false, "COLLATION", SECTION_PRE_DATA,
11375                                  q->data, delq->data, NULL,
11376                                  NULL, 0,
11377                                  NULL, NULL);
11378
11379         /* Dump Collation Comments */
11380         dumpComment(fout, labelq->data,
11381                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11382                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11383
11384         PQclear(res);
11385
11386         destroyPQExpBuffer(query);
11387         destroyPQExpBuffer(q);
11388         destroyPQExpBuffer(delq);
11389         destroyPQExpBuffer(labelq);
11390 }
11391
11392 /*
11393  * dumpConversion
11394  *        write out a single conversion definition
11395  */
11396 static void
11397 dumpConversion(Archive *fout, ConvInfo *convinfo)
11398 {
11399         PQExpBuffer query;
11400         PQExpBuffer q;
11401         PQExpBuffer delq;
11402         PQExpBuffer labelq;
11403         PGresult   *res;
11404         int                     i_conforencoding;
11405         int                     i_contoencoding;
11406         int                     i_conproc;
11407         int                     i_condefault;
11408         const char *conforencoding;
11409         const char *contoencoding;
11410         const char *conproc;
11411         bool            condefault;
11412
11413         /* Skip if not to be dumped */
11414         if (!convinfo->dobj.dump || dataOnly)
11415                 return;
11416
11417         query = createPQExpBuffer();
11418         q = createPQExpBuffer();
11419         delq = createPQExpBuffer();
11420         labelq = createPQExpBuffer();
11421
11422         /* Make sure we are in proper schema */
11423         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11424
11425         /* Get conversion-specific details */
11426         appendPQExpBuffer(query, "SELECT "
11427                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11428                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11429                                           "conproc, condefault "
11430                                           "FROM pg_catalog.pg_conversion c "
11431                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11432                                           convinfo->dobj.catId.oid);
11433
11434         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11435
11436         i_conforencoding = PQfnumber(res, "conforencoding");
11437         i_contoencoding = PQfnumber(res, "contoencoding");
11438         i_conproc = PQfnumber(res, "conproc");
11439         i_condefault = PQfnumber(res, "condefault");
11440
11441         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11442         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11443         conproc = PQgetvalue(res, 0, i_conproc);
11444         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11445
11446         /*
11447          * DROP must be fully qualified in case same name appears in pg_catalog
11448          */
11449         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11450                                           fmtId(convinfo->dobj.namespace->dobj.name));
11451         appendPQExpBuffer(delq, ".%s;\n",
11452                                           fmtId(convinfo->dobj.name));
11453
11454         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11455                                           (condefault) ? "DEFAULT " : "",
11456                                           fmtId(convinfo->dobj.name));
11457         appendStringLiteralAH(q, conforencoding, fout);
11458         appendPQExpBufferStr(q, " TO ");
11459         appendStringLiteralAH(q, contoencoding, fout);
11460         /* regproc is automatically quoted in 7.3 and above */
11461         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11462
11463         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11464
11465         if (binary_upgrade)
11466                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11467
11468         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11469                                  convinfo->dobj.name,
11470                                  convinfo->dobj.namespace->dobj.name,
11471                                  NULL,
11472                                  convinfo->rolname,
11473                                  false, "CONVERSION", SECTION_PRE_DATA,
11474                                  q->data, delq->data, NULL,
11475                                  NULL, 0,
11476                                  NULL, NULL);
11477
11478         /* Dump Conversion Comments */
11479         dumpComment(fout, labelq->data,
11480                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11481                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11482
11483         PQclear(res);
11484
11485         destroyPQExpBuffer(query);
11486         destroyPQExpBuffer(q);
11487         destroyPQExpBuffer(delq);
11488         destroyPQExpBuffer(labelq);
11489 }
11490
11491 /*
11492  * format_aggregate_signature: generate aggregate name and argument list
11493  *
11494  * The argument type names are qualified if needed.  The aggregate name
11495  * is never qualified.
11496  */
11497 static char *
11498 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11499 {
11500         PQExpBufferData buf;
11501         int                     j;
11502
11503         initPQExpBuffer(&buf);
11504         if (honor_quotes)
11505                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
11506         else
11507                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
11508
11509         if (agginfo->aggfn.nargs == 0)
11510                 appendPQExpBuffer(&buf, "(*)");
11511         else
11512         {
11513                 appendPQExpBufferChar(&buf, '(');
11514                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11515                 {
11516                         char       *typname;
11517
11518                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11519                                                                                    zeroAsOpaque);
11520
11521                         appendPQExpBuffer(&buf, "%s%s",
11522                                                           (j > 0) ? ", " : "",
11523                                                           typname);
11524                         free(typname);
11525                 }
11526                 appendPQExpBufferChar(&buf, ')');
11527         }
11528         return buf.data;
11529 }
11530
11531 /*
11532  * dumpAgg
11533  *        write out a single aggregate definition
11534  */
11535 static void
11536 dumpAgg(Archive *fout, AggInfo *agginfo)
11537 {
11538         PQExpBuffer query;
11539         PQExpBuffer q;
11540         PQExpBuffer delq;
11541         PQExpBuffer labelq;
11542         PQExpBuffer details;
11543         char       *aggsig;                     /* identity signature */
11544         char       *aggfullsig = NULL;          /* full signature */
11545         char       *aggsig_tag;
11546         PGresult   *res;
11547         int                     i_aggtransfn;
11548         int                     i_aggfinalfn;
11549         int                     i_aggsortop;
11550         int                     i_hypothetical;
11551         int                     i_aggtranstype;
11552         int                     i_aggtransspace;
11553         int                     i_agginitval;
11554         int                     i_convertok;
11555         const char *aggtransfn;
11556         const char *aggfinalfn;
11557         const char *aggsortop;
11558         char       *aggsortconvop;
11559         bool            hypothetical;
11560         const char *aggtranstype;
11561         const char *aggtransspace;
11562         const char *agginitval;
11563         bool            convertok;
11564
11565         /* Skip if not to be dumped */
11566         if (!agginfo->aggfn.dobj.dump || dataOnly)
11567                 return;
11568
11569         query = createPQExpBuffer();
11570         q = createPQExpBuffer();
11571         delq = createPQExpBuffer();
11572         labelq = createPQExpBuffer();
11573         details = createPQExpBuffer();
11574
11575         /* Make sure we are in proper schema */
11576         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11577
11578         /* Get aggregate-specific details */
11579         if (fout->remoteVersion >= 90400)
11580         {
11581                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11582                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11583                                                   "aggsortop::pg_catalog.regoperator, "
11584                                                   "(aggkind = 'h') as hypothetical, "
11585                                                   "aggtransspace, agginitval, "
11586                                                   "'t'::boolean AS convertok, "
11587                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11588                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11589                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11590                                                   "WHERE a.aggfnoid = p.oid "
11591                                                   "AND p.oid = '%u'::pg_catalog.oid",
11592                                                   agginfo->aggfn.dobj.catId.oid);
11593         }
11594         else if (fout->remoteVersion >= 80400)
11595         {
11596                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11597                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11598                                                   "aggsortop::pg_catalog.regoperator, "
11599                                                   "false as hypothetical, "
11600                                                   "0 AS aggtransspace, agginitval, "
11601                                                   "'t'::boolean AS convertok, "
11602                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11603                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11604                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11605                                                   "WHERE a.aggfnoid = p.oid "
11606                                                   "AND p.oid = '%u'::pg_catalog.oid",
11607                                                   agginfo->aggfn.dobj.catId.oid);
11608         }
11609         else if (fout->remoteVersion >= 80100)
11610         {
11611                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11612                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11613                                                   "aggsortop::pg_catalog.regoperator, "
11614                                                   "false as hypothetical, "
11615                                                   "0 AS aggtransspace, agginitval, "
11616                                                   "'t'::boolean AS convertok "
11617                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11618                                                   "WHERE a.aggfnoid = p.oid "
11619                                                   "AND p.oid = '%u'::pg_catalog.oid",
11620                                                   agginfo->aggfn.dobj.catId.oid);
11621         }
11622         else if (fout->remoteVersion >= 70300)
11623         {
11624                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11625                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11626                                                   "0 AS aggsortop, "
11627                                                   "'f'::boolean as hypothetical, "
11628                                                   "0 AS aggtransspace, agginitval, "
11629                                                   "'t'::boolean AS convertok "
11630                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11631                                                   "WHERE a.aggfnoid = p.oid "
11632                                                   "AND p.oid = '%u'::pg_catalog.oid",
11633                                                   agginfo->aggfn.dobj.catId.oid);
11634         }
11635         else if (fout->remoteVersion >= 70100)
11636         {
11637                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11638                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11639                                                   "0 AS aggsortop, "
11640                                                   "'f'::boolean as hypothetical, "
11641                                                   "0 AS aggtransspace, agginitval, "
11642                                                   "'t'::boolean AS convertok "
11643                                                   "FROM pg_aggregate "
11644                                                   "WHERE oid = '%u'::oid",
11645                                                   agginfo->aggfn.dobj.catId.oid);
11646         }
11647         else
11648         {
11649                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11650                                                   "aggfinalfn, "
11651                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11652                                                   "0 AS aggsortop, "
11653                                                   "'f'::boolean as hypothetical, "
11654                                                   "0 AS aggtransspace, agginitval1 AS agginitval, "
11655                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11656                                                   "FROM pg_aggregate "
11657                                                   "WHERE oid = '%u'::oid",
11658                                                   agginfo->aggfn.dobj.catId.oid);
11659         }
11660
11661         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11662
11663         i_aggtransfn = PQfnumber(res, "aggtransfn");
11664         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11665         i_aggsortop = PQfnumber(res, "aggsortop");
11666         i_hypothetical = PQfnumber(res, "hypothetical");
11667         i_aggtranstype = PQfnumber(res, "aggtranstype");
11668         i_aggtransspace = PQfnumber(res, "aggtransspace");
11669         i_agginitval = PQfnumber(res, "agginitval");
11670         i_convertok = PQfnumber(res, "convertok");
11671
11672         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11673         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11674         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11675         hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
11676         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11677         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
11678         agginitval = PQgetvalue(res, 0, i_agginitval);
11679         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11680
11681         if (fout->remoteVersion >= 80400)
11682         {
11683                 /* 8.4 or later; we rely on server-side code for most of the work */
11684                 char       *funcargs;
11685                 char       *funciargs;
11686
11687                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11688                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11689                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
11690                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
11691         }
11692         else
11693                 /* pre-8.4, do it ourselves */
11694                 aggsig = format_aggregate_signature(agginfo, fout, true);
11695
11696         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11697
11698         if (!convertok)
11699         {
11700                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11701                                   aggsig);
11702
11703                 if (aggfullsig)
11704                         free(aggfullsig);
11705
11706                 free(aggsig);
11707
11708                 return;
11709         }
11710
11711         if (fout->remoteVersion >= 70300)
11712         {
11713                 /* If using 7.3's regproc or regtype, data is already quoted */
11714                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11715                                                   aggtransfn,
11716                                                   aggtranstype);
11717         }
11718         else if (fout->remoteVersion >= 70100)
11719         {
11720                 /* format_type quotes, regproc does not */
11721                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11722                                                   fmtId(aggtransfn),
11723                                                   aggtranstype);
11724         }
11725         else
11726         {
11727                 /* need quotes all around */
11728                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11729                                                   fmtId(aggtransfn));
11730                 appendPQExpBuffer(details, "    STYPE = %s",
11731                                                   fmtId(aggtranstype));
11732         }
11733
11734         if (strcmp(aggtransspace, "0") != 0)
11735         {
11736                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
11737                                                   aggtransspace);
11738         }
11739
11740         if (!PQgetisnull(res, 0, i_agginitval))
11741         {
11742                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
11743                 appendStringLiteralAH(details, agginitval, fout);
11744         }
11745
11746         if (strcmp(aggfinalfn, "-") != 0)
11747         {
11748                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11749                                                   aggfinalfn);
11750         }
11751
11752         aggsortconvop = convertOperatorReference(fout, aggsortop);
11753         if (aggsortconvop)
11754         {
11755                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11756                                                   aggsortconvop);
11757                 free(aggsortconvop);
11758         }
11759
11760         if (hypothetical)
11761                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
11762
11763         /*
11764          * DROP must be fully qualified in case same name appears in pg_catalog
11765          */
11766         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11767                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11768                                           aggsig);
11769
11770         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11771                                           aggfullsig ? aggfullsig : aggsig, details->data);
11772
11773         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11774
11775         if (binary_upgrade)
11776                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11777
11778         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11779                                  aggsig_tag,
11780                                  agginfo->aggfn.dobj.namespace->dobj.name,
11781                                  NULL,
11782                                  agginfo->aggfn.rolname,
11783                                  false, "AGGREGATE", SECTION_PRE_DATA,
11784                                  q->data, delq->data, NULL,
11785                                  NULL, 0,
11786                                  NULL, NULL);
11787
11788         /* Dump Aggregate Comments */
11789         dumpComment(fout, labelq->data,
11790                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11791                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11792         dumpSecLabel(fout, labelq->data,
11793                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11794                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11795
11796         /*
11797          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11798          * command look like a function's GRANT; in particular this affects the
11799          * syntax for zero-argument aggregates and ordered-set aggregates.
11800          */
11801         free(aggsig);
11802         free(aggsig_tag);
11803
11804         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11805         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11806
11807         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11808                         "FUNCTION",
11809                         aggsig, NULL, aggsig_tag,
11810                         agginfo->aggfn.dobj.namespace->dobj.name,
11811                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11812
11813         free(aggsig);
11814         if (aggfullsig)
11815                 free(aggfullsig);
11816         free(aggsig_tag);
11817
11818         PQclear(res);
11819
11820         destroyPQExpBuffer(query);
11821         destroyPQExpBuffer(q);
11822         destroyPQExpBuffer(delq);
11823         destroyPQExpBuffer(labelq);
11824         destroyPQExpBuffer(details);
11825 }
11826
11827 /*
11828  * dumpTSParser
11829  *        write out a single text search parser
11830  */
11831 static void
11832 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11833 {
11834         PQExpBuffer q;
11835         PQExpBuffer delq;
11836         PQExpBuffer labelq;
11837
11838         /* Skip if not to be dumped */
11839         if (!prsinfo->dobj.dump || dataOnly)
11840                 return;
11841
11842         q = createPQExpBuffer();
11843         delq = createPQExpBuffer();
11844         labelq = createPQExpBuffer();
11845
11846         /* Make sure we are in proper schema */
11847         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11848
11849         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11850                                           fmtId(prsinfo->dobj.name));
11851
11852         appendPQExpBuffer(q, "    START = %s,\n",
11853                                           convertTSFunction(fout, prsinfo->prsstart));
11854         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11855                                           convertTSFunction(fout, prsinfo->prstoken));
11856         appendPQExpBuffer(q, "    END = %s,\n",
11857                                           convertTSFunction(fout, prsinfo->prsend));
11858         if (prsinfo->prsheadline != InvalidOid)
11859                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11860                                                   convertTSFunction(fout, prsinfo->prsheadline));
11861         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11862                                           convertTSFunction(fout, prsinfo->prslextype));
11863
11864         /*
11865          * DROP must be fully qualified in case same name appears in pg_catalog
11866          */
11867         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11868                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11869         appendPQExpBuffer(delq, ".%s;\n",
11870                                           fmtId(prsinfo->dobj.name));
11871
11872         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11873                                           fmtId(prsinfo->dobj.name));
11874
11875         if (binary_upgrade)
11876                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11877
11878         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11879                                  prsinfo->dobj.name,
11880                                  prsinfo->dobj.namespace->dobj.name,
11881                                  NULL,
11882                                  "",
11883                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11884                                  q->data, delq->data, NULL,
11885                                  NULL, 0,
11886                                  NULL, NULL);
11887
11888         /* Dump Parser Comments */
11889         dumpComment(fout, labelq->data,
11890                                 NULL, "",
11891                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11892
11893         destroyPQExpBuffer(q);
11894         destroyPQExpBuffer(delq);
11895         destroyPQExpBuffer(labelq);
11896 }
11897
11898 /*
11899  * dumpTSDictionary
11900  *        write out a single text search dictionary
11901  */
11902 static void
11903 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11904 {
11905         PQExpBuffer q;
11906         PQExpBuffer delq;
11907         PQExpBuffer labelq;
11908         PQExpBuffer query;
11909         PGresult   *res;
11910         char       *nspname;
11911         char       *tmplname;
11912
11913         /* Skip if not to be dumped */
11914         if (!dictinfo->dobj.dump || dataOnly)
11915                 return;
11916
11917         q = createPQExpBuffer();
11918         delq = createPQExpBuffer();
11919         labelq = createPQExpBuffer();
11920         query = createPQExpBuffer();
11921
11922         /* Fetch name and namespace of the dictionary's template */
11923         selectSourceSchema(fout, "pg_catalog");
11924         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11925                                           "FROM pg_ts_template p, pg_namespace n "
11926                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11927                                           dictinfo->dicttemplate);
11928         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11929         nspname = PQgetvalue(res, 0, 0);
11930         tmplname = PQgetvalue(res, 0, 1);
11931
11932         /* Make sure we are in proper schema */
11933         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11934
11935         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11936                                           fmtId(dictinfo->dobj.name));
11937
11938         appendPQExpBufferStr(q, "    TEMPLATE = ");
11939         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11940                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11941         appendPQExpBufferStr(q, fmtId(tmplname));
11942
11943         PQclear(res);
11944
11945         /* the dictinitoption can be dumped straight into the command */
11946         if (dictinfo->dictinitoption)
11947                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11948
11949         appendPQExpBufferStr(q, " );\n");
11950
11951         /*
11952          * DROP must be fully qualified in case same name appears in pg_catalog
11953          */
11954         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11955                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11956         appendPQExpBuffer(delq, ".%s;\n",
11957                                           fmtId(dictinfo->dobj.name));
11958
11959         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11960                                           fmtId(dictinfo->dobj.name));
11961
11962         if (binary_upgrade)
11963                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11964
11965         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11966                                  dictinfo->dobj.name,
11967                                  dictinfo->dobj.namespace->dobj.name,
11968                                  NULL,
11969                                  dictinfo->rolname,
11970                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11971                                  q->data, delq->data, NULL,
11972                                  NULL, 0,
11973                                  NULL, NULL);
11974
11975         /* Dump Dictionary Comments */
11976         dumpComment(fout, labelq->data,
11977                                 NULL, dictinfo->rolname,
11978                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11979
11980         destroyPQExpBuffer(q);
11981         destroyPQExpBuffer(delq);
11982         destroyPQExpBuffer(labelq);
11983         destroyPQExpBuffer(query);
11984 }
11985
11986 /*
11987  * dumpTSTemplate
11988  *        write out a single text search template
11989  */
11990 static void
11991 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11992 {
11993         PQExpBuffer q;
11994         PQExpBuffer delq;
11995         PQExpBuffer labelq;
11996
11997         /* Skip if not to be dumped */
11998         if (!tmplinfo->dobj.dump || dataOnly)
11999                 return;
12000
12001         q = createPQExpBuffer();
12002         delq = createPQExpBuffer();
12003         labelq = createPQExpBuffer();
12004
12005         /* Make sure we are in proper schema */
12006         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
12007
12008         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
12009                                           fmtId(tmplinfo->dobj.name));
12010
12011         if (tmplinfo->tmplinit != InvalidOid)
12012                 appendPQExpBuffer(q, "    INIT = %s,\n",
12013                                                   convertTSFunction(fout, tmplinfo->tmplinit));
12014         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
12015                                           convertTSFunction(fout, tmplinfo->tmpllexize));
12016
12017         /*
12018          * DROP must be fully qualified in case same name appears in pg_catalog
12019          */
12020         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
12021                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
12022         appendPQExpBuffer(delq, ".%s;\n",
12023                                           fmtId(tmplinfo->dobj.name));
12024
12025         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
12026                                           fmtId(tmplinfo->dobj.name));
12027
12028         if (binary_upgrade)
12029                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
12030
12031         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
12032                                  tmplinfo->dobj.name,
12033                                  tmplinfo->dobj.namespace->dobj.name,
12034                                  NULL,
12035                                  "",
12036                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
12037                                  q->data, delq->data, NULL,
12038                                  NULL, 0,
12039                                  NULL, NULL);
12040
12041         /* Dump Template Comments */
12042         dumpComment(fout, labelq->data,
12043                                 NULL, "",
12044                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
12045
12046         destroyPQExpBuffer(q);
12047         destroyPQExpBuffer(delq);
12048         destroyPQExpBuffer(labelq);
12049 }
12050
12051 /*
12052  * dumpTSConfig
12053  *        write out a single text search configuration
12054  */
12055 static void
12056 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
12057 {
12058         PQExpBuffer q;
12059         PQExpBuffer delq;
12060         PQExpBuffer labelq;
12061         PQExpBuffer query;
12062         PGresult   *res;
12063         char       *nspname;
12064         char       *prsname;
12065         int                     ntups,
12066                                 i;
12067         int                     i_tokenname;
12068         int                     i_dictname;
12069
12070         /* Skip if not to be dumped */
12071         if (!cfginfo->dobj.dump || dataOnly)
12072                 return;
12073
12074         q = createPQExpBuffer();
12075         delq = createPQExpBuffer();
12076         labelq = createPQExpBuffer();
12077         query = createPQExpBuffer();
12078
12079         /* Fetch name and namespace of the config's parser */
12080         selectSourceSchema(fout, "pg_catalog");
12081         appendPQExpBuffer(query, "SELECT nspname, prsname "
12082                                           "FROM pg_ts_parser p, pg_namespace n "
12083                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
12084                                           cfginfo->cfgparser);
12085         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12086         nspname = PQgetvalue(res, 0, 0);
12087         prsname = PQgetvalue(res, 0, 1);
12088
12089         /* Make sure we are in proper schema */
12090         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
12091
12092         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
12093                                           fmtId(cfginfo->dobj.name));
12094
12095         appendPQExpBufferStr(q, "    PARSER = ");
12096         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
12097                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
12098         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
12099
12100         PQclear(res);
12101
12102         resetPQExpBuffer(query);
12103         appendPQExpBuffer(query,
12104                                           "SELECT \n"
12105                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
12106                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
12107                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
12108                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
12109                                           "WHERE m.mapcfg = '%u' \n"
12110                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
12111                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
12112
12113         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12114         ntups = PQntuples(res);
12115
12116         i_tokenname = PQfnumber(res, "tokenname");
12117         i_dictname = PQfnumber(res, "dictname");
12118
12119         for (i = 0; i < ntups; i++)
12120         {
12121                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
12122                 char       *dictname = PQgetvalue(res, i, i_dictname);
12123
12124                 if (i == 0 ||
12125                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
12126                 {
12127                         /* starting a new token type, so start a new command */
12128                         if (i > 0)
12129                                 appendPQExpBufferStr(q, ";\n");
12130                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
12131                                                           fmtId(cfginfo->dobj.name));
12132                         /* tokenname needs quoting, dictname does NOT */
12133                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
12134                                                           fmtId(tokenname), dictname);
12135                 }
12136                 else
12137                         appendPQExpBuffer(q, ", %s", dictname);
12138         }
12139
12140         if (ntups > 0)
12141                 appendPQExpBufferStr(q, ";\n");
12142
12143         PQclear(res);
12144
12145         /*
12146          * DROP must be fully qualified in case same name appears in pg_catalog
12147          */
12148         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
12149                                           fmtId(cfginfo->dobj.namespace->dobj.name));
12150         appendPQExpBuffer(delq, ".%s;\n",
12151                                           fmtId(cfginfo->dobj.name));
12152
12153         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
12154                                           fmtId(cfginfo->dobj.name));
12155
12156         if (binary_upgrade)
12157                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
12158
12159         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
12160                                  cfginfo->dobj.name,
12161                                  cfginfo->dobj.namespace->dobj.name,
12162                                  NULL,
12163                                  cfginfo->rolname,
12164                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
12165                                  q->data, delq->data, NULL,
12166                                  NULL, 0,
12167                                  NULL, NULL);
12168
12169         /* Dump Configuration Comments */
12170         dumpComment(fout, labelq->data,
12171                                 NULL, cfginfo->rolname,
12172                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
12173
12174         destroyPQExpBuffer(q);
12175         destroyPQExpBuffer(delq);
12176         destroyPQExpBuffer(labelq);
12177         destroyPQExpBuffer(query);
12178 }
12179
12180 /*
12181  * dumpForeignDataWrapper
12182  *        write out a single foreign-data wrapper definition
12183  */
12184 static void
12185 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
12186 {
12187         PQExpBuffer q;
12188         PQExpBuffer delq;
12189         PQExpBuffer labelq;
12190         char       *qfdwname;
12191
12192         /* Skip if not to be dumped */
12193         if (!fdwinfo->dobj.dump || dataOnly)
12194                 return;
12195
12196         /*
12197          * FDWs that belong to an extension are dumped based on their "dump"
12198          * field. Otherwise omit them if we are only dumping some specific object.
12199          */
12200         if (!fdwinfo->dobj.ext_member)
12201                 if (!include_everything)
12202                         return;
12203
12204         q = createPQExpBuffer();
12205         delq = createPQExpBuffer();
12206         labelq = createPQExpBuffer();
12207
12208         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
12209
12210         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
12211                                           qfdwname);
12212
12213         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
12214                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
12215
12216         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
12217                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
12218
12219         if (strlen(fdwinfo->fdwoptions) > 0)
12220                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12221
12222         appendPQExpBufferStr(q, ";\n");
12223
12224         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12225                                           qfdwname);
12226
12227         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12228                                           qfdwname);
12229
12230         if (binary_upgrade)
12231                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12232
12233         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12234                                  fdwinfo->dobj.name,
12235                                  NULL,
12236                                  NULL,
12237                                  fdwinfo->rolname,
12238                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12239                                  q->data, delq->data, NULL,
12240                                  NULL, 0,
12241                                  NULL, NULL);
12242
12243         /* Handle the ACL */
12244         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12245                         "FOREIGN DATA WRAPPER",
12246                         qfdwname, NULL, fdwinfo->dobj.name,
12247                         NULL, fdwinfo->rolname,
12248                         fdwinfo->fdwacl);
12249
12250         /* Dump Foreign Data Wrapper Comments */
12251         dumpComment(fout, labelq->data,
12252                                 NULL, fdwinfo->rolname,
12253                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12254
12255         free(qfdwname);
12256
12257         destroyPQExpBuffer(q);
12258         destroyPQExpBuffer(delq);
12259         destroyPQExpBuffer(labelq);
12260 }
12261
12262 /*
12263  * dumpForeignServer
12264  *        write out a foreign server definition
12265  */
12266 static void
12267 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12268 {
12269         PQExpBuffer q;
12270         PQExpBuffer delq;
12271         PQExpBuffer labelq;
12272         PQExpBuffer query;
12273         PGresult   *res;
12274         char       *qsrvname;
12275         char       *fdwname;
12276
12277         /* Skip if not to be dumped */
12278         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12279                 return;
12280
12281         q = createPQExpBuffer();
12282         delq = createPQExpBuffer();
12283         labelq = createPQExpBuffer();
12284         query = createPQExpBuffer();
12285
12286         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12287
12288         /* look up the foreign-data wrapper */
12289         selectSourceSchema(fout, "pg_catalog");
12290         appendPQExpBuffer(query, "SELECT fdwname "
12291                                           "FROM pg_foreign_data_wrapper w "
12292                                           "WHERE w.oid = '%u'",
12293                                           srvinfo->srvfdw);
12294         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12295         fdwname = PQgetvalue(res, 0, 0);
12296
12297         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12298         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12299         {
12300                 appendPQExpBufferStr(q, " TYPE ");
12301                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12302         }
12303         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12304         {
12305                 appendPQExpBufferStr(q, " VERSION ");
12306                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12307         }
12308
12309         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
12310         appendPQExpBufferStr(q, fmtId(fdwname));
12311
12312         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12313                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12314
12315         appendPQExpBufferStr(q, ";\n");
12316
12317         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12318                                           qsrvname);
12319
12320         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12321
12322         if (binary_upgrade)
12323                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12324
12325         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12326                                  srvinfo->dobj.name,
12327                                  NULL,
12328                                  NULL,
12329                                  srvinfo->rolname,
12330                                  false, "SERVER", SECTION_PRE_DATA,
12331                                  q->data, delq->data, NULL,
12332                                  NULL, 0,
12333                                  NULL, NULL);
12334
12335         /* Handle the ACL */
12336         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12337                         "FOREIGN SERVER",
12338                         qsrvname, NULL, srvinfo->dobj.name,
12339                         NULL, srvinfo->rolname,
12340                         srvinfo->srvacl);
12341
12342         /* Dump user mappings */
12343         dumpUserMappings(fout,
12344                                          srvinfo->dobj.name, NULL,
12345                                          srvinfo->rolname,
12346                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12347
12348         /* Dump Foreign Server Comments */
12349         dumpComment(fout, labelq->data,
12350                                 NULL, srvinfo->rolname,
12351                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12352
12353         free(qsrvname);
12354
12355         destroyPQExpBuffer(q);
12356         destroyPQExpBuffer(delq);
12357         destroyPQExpBuffer(labelq);
12358 }
12359
12360 /*
12361  * dumpUserMappings
12362  *
12363  * This routine is used to dump any user mappings associated with the
12364  * server handed to this routine. Should be called after ArchiveEntry()
12365  * for the server.
12366  */
12367 static void
12368 dumpUserMappings(Archive *fout,
12369                                  const char *servername, const char *namespace,
12370                                  const char *owner,
12371                                  CatalogId catalogId, DumpId dumpId)
12372 {
12373         PQExpBuffer q;
12374         PQExpBuffer delq;
12375         PQExpBuffer query;
12376         PQExpBuffer tag;
12377         PGresult   *res;
12378         int                     ntups;
12379         int                     i_usename;
12380         int                     i_umoptions;
12381         int                     i;
12382
12383         q = createPQExpBuffer();
12384         tag = createPQExpBuffer();
12385         delq = createPQExpBuffer();
12386         query = createPQExpBuffer();
12387
12388         /*
12389          * We read from the publicly accessible view pg_user_mappings, so as not
12390          * to fail if run by a non-superuser.  Note that the view will show
12391          * umoptions as null if the user hasn't got privileges for the associated
12392          * server; this means that pg_dump will dump such a mapping, but with no
12393          * OPTIONS clause.      A possible alternative is to skip such mappings
12394          * altogether, but it's not clear that that's an improvement.
12395          */
12396         selectSourceSchema(fout, "pg_catalog");
12397
12398         appendPQExpBuffer(query,
12399                                           "SELECT usename, "
12400                                           "array_to_string(ARRAY("
12401                                           "SELECT quote_ident(option_name) || ' ' || "
12402                                           "quote_literal(option_value) "
12403                                           "FROM pg_options_to_table(umoptions) "
12404                                           "ORDER BY option_name"
12405                                           "), E',\n    ') AS umoptions "
12406                                           "FROM pg_user_mappings "
12407                                           "WHERE srvid = '%u' "
12408                                           "ORDER BY usename",
12409                                           catalogId.oid);
12410
12411         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12412
12413         ntups = PQntuples(res);
12414         i_usename = PQfnumber(res, "usename");
12415         i_umoptions = PQfnumber(res, "umoptions");
12416
12417         for (i = 0; i < ntups; i++)
12418         {
12419                 char       *usename;
12420                 char       *umoptions;
12421
12422                 usename = PQgetvalue(res, i, i_usename);
12423                 umoptions = PQgetvalue(res, i, i_umoptions);
12424
12425                 resetPQExpBuffer(q);
12426                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12427                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12428
12429                 if (umoptions && strlen(umoptions) > 0)
12430                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12431
12432                 appendPQExpBufferStr(q, ";\n");
12433
12434                 resetPQExpBuffer(delq);
12435                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12436                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12437
12438                 resetPQExpBuffer(tag);
12439                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12440                                                   usename, servername);
12441
12442                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12443                                          tag->data,
12444                                          namespace,
12445                                          NULL,
12446                                          owner, false,
12447                                          "USER MAPPING", SECTION_PRE_DATA,
12448                                          q->data, delq->data, NULL,
12449                                          &dumpId, 1,
12450                                          NULL, NULL);
12451         }
12452
12453         PQclear(res);
12454
12455         destroyPQExpBuffer(query);
12456         destroyPQExpBuffer(delq);
12457         destroyPQExpBuffer(tag);
12458         destroyPQExpBuffer(q);
12459 }
12460
12461 /*
12462  * Write out default privileges information
12463  */
12464 static void
12465 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12466 {
12467         PQExpBuffer q;
12468         PQExpBuffer tag;
12469         const char *type;
12470
12471         /* Skip if not to be dumped */
12472         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12473                 return;
12474
12475         q = createPQExpBuffer();
12476         tag = createPQExpBuffer();
12477
12478         switch (daclinfo->defaclobjtype)
12479         {
12480                 case DEFACLOBJ_RELATION:
12481                         type = "TABLES";
12482                         break;
12483                 case DEFACLOBJ_SEQUENCE:
12484                         type = "SEQUENCES";
12485                         break;
12486                 case DEFACLOBJ_FUNCTION:
12487                         type = "FUNCTIONS";
12488                         break;
12489                 case DEFACLOBJ_TYPE:
12490                         type = "TYPES";
12491                         break;
12492                 default:
12493                         /* shouldn't get here */
12494                         exit_horribly(NULL,
12495                                           "unrecognized object type in default privileges: %d\n",
12496                                                   (int) daclinfo->defaclobjtype);
12497                         type = "";                      /* keep compiler quiet */
12498         }
12499
12500         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12501
12502         /* build the actual command(s) for this tuple */
12503         if (!buildDefaultACLCommands(type,
12504                                                                  daclinfo->dobj.namespace != NULL ?
12505                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12506                                                                  daclinfo->defaclacl,
12507                                                                  daclinfo->defaclrole,
12508                                                                  fout->remoteVersion,
12509                                                                  q))
12510                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12511                                           daclinfo->defaclacl);
12512
12513         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12514                                  tag->data,
12515            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12516                                  NULL,
12517                                  daclinfo->defaclrole,
12518                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12519                                  q->data, "", NULL,
12520                                  NULL, 0,
12521                                  NULL, NULL);
12522
12523         destroyPQExpBuffer(tag);
12524         destroyPQExpBuffer(q);
12525 }
12526
12527 /*----------
12528  * Write out grant/revoke information
12529  *
12530  * 'objCatId' is the catalog ID of the underlying object.
12531  * 'objDumpId' is the dump ID of the underlying object.
12532  * 'type' must be one of
12533  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12534  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12535  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12536  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12537  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12538  * 'nspname' is the namespace the object is in (NULL if none).
12539  * 'owner' is the owner, NULL if there is no owner (for languages).
12540  * 'acls' is the string read out of the fooacl system catalog field;
12541  *              it will be parsed here.
12542  *----------
12543  */
12544 static void
12545 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12546                 const char *type, const char *name, const char *subname,
12547                 const char *tag, const char *nspname, const char *owner,
12548                 const char *acls)
12549 {
12550         PQExpBuffer sql;
12551
12552         /* Do nothing if ACL dump is not enabled */
12553         if (aclsSkip)
12554                 return;
12555
12556         /* --data-only skips ACLs *except* BLOB ACLs */
12557         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12558                 return;
12559
12560         sql = createPQExpBuffer();
12561
12562         if (!buildACLCommands(name, subname, type, acls, owner,
12563                                                   "", fout->remoteVersion, sql))
12564                 exit_horribly(NULL,
12565                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12566                                           acls, name, type);
12567
12568         if (sql->len > 0)
12569                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12570                                          tag, nspname,
12571                                          NULL,
12572                                          owner ? owner : "",
12573                                          false, "ACL", SECTION_NONE,
12574                                          sql->data, "", NULL,
12575                                          &(objDumpId), 1,
12576                                          NULL, NULL);
12577
12578         destroyPQExpBuffer(sql);
12579 }
12580
12581 /*
12582  * dumpSecLabel
12583  *
12584  * This routine is used to dump any security labels associated with the
12585  * object handed to this routine. The routine takes a constant character
12586  * string for the target part of the security-label command, plus
12587  * the namespace and owner of the object (for labeling the ArchiveEntry),
12588  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12589  * plus the dump ID for the object (for setting a dependency).
12590  * If a matching pg_seclabel entry is found, it is dumped.
12591  *
12592  * Note: although this routine takes a dumpId for dependency purposes,
12593  * that purpose is just to mark the dependency in the emitted dump file
12594  * for possible future use by pg_restore.  We do NOT use it for determining
12595  * ordering of the label in the dump file, because this routine is called
12596  * after dependency sorting occurs.  This routine should be called just after
12597  * calling ArchiveEntry() for the specified object.
12598  */
12599 static void
12600 dumpSecLabel(Archive *fout, const char *target,
12601                          const char *namespace, const char *owner,
12602                          CatalogId catalogId, int subid, DumpId dumpId)
12603 {
12604         SecLabelItem *labels;
12605         int                     nlabels;
12606         int                     i;
12607         PQExpBuffer query;
12608
12609         /* do nothing, if --no-security-labels is supplied */
12610         if (no_security_labels)
12611                 return;
12612
12613         /* Comments are schema not data ... except blob comments are data */
12614         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12615         {
12616                 if (dataOnly)
12617                         return;
12618         }
12619         else
12620         {
12621                 if (schemaOnly)
12622                         return;
12623         }
12624
12625         /* Search for security labels associated with catalogId, using table */
12626         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12627
12628         query = createPQExpBuffer();
12629
12630         for (i = 0; i < nlabels; i++)
12631         {
12632                 /*
12633                  * Ignore label entries for which the subid doesn't match.
12634                  */
12635                 if (labels[i].objsubid != subid)
12636                         continue;
12637
12638                 appendPQExpBuffer(query,
12639                                                   "SECURITY LABEL FOR %s ON %s IS ",
12640                                                   fmtId(labels[i].provider), target);
12641                 appendStringLiteralAH(query, labels[i].label, fout);
12642                 appendPQExpBufferStr(query, ";\n");
12643         }
12644
12645         if (query->len > 0)
12646         {
12647                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12648                                          target, namespace, NULL, owner,
12649                                          false, "SECURITY LABEL", SECTION_NONE,
12650                                          query->data, "", NULL,
12651                                          &(dumpId), 1,
12652                                          NULL, NULL);
12653         }
12654         destroyPQExpBuffer(query);
12655 }
12656
12657 /*
12658  * dumpTableSecLabel
12659  *
12660  * As above, but dump security label for both the specified table (or view)
12661  * and its columns.
12662  */
12663 static void
12664 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12665 {
12666         SecLabelItem *labels;
12667         int                     nlabels;
12668         int                     i;
12669         PQExpBuffer query;
12670         PQExpBuffer target;
12671
12672         /* do nothing, if --no-security-labels is supplied */
12673         if (no_security_labels)
12674                 return;
12675
12676         /* SecLabel are SCHEMA not data */
12677         if (dataOnly)
12678                 return;
12679
12680         /* Search for comments associated with relation, using table */
12681         nlabels = findSecLabels(fout,
12682                                                         tbinfo->dobj.catId.tableoid,
12683                                                         tbinfo->dobj.catId.oid,
12684                                                         &labels);
12685
12686         /* If security labels exist, build SECURITY LABEL statements */
12687         if (nlabels <= 0)
12688                 return;
12689
12690         query = createPQExpBuffer();
12691         target = createPQExpBuffer();
12692
12693         for (i = 0; i < nlabels; i++)
12694         {
12695                 const char *colname;
12696                 const char *provider = labels[i].provider;
12697                 const char *label = labels[i].label;
12698                 int                     objsubid = labels[i].objsubid;
12699
12700                 resetPQExpBuffer(target);
12701                 if (objsubid == 0)
12702                 {
12703                         appendPQExpBuffer(target, "%s %s", reltypename,
12704                                                           fmtId(tbinfo->dobj.name));
12705                 }
12706                 else
12707                 {
12708                         colname = getAttrName(objsubid, tbinfo);
12709                         /* first fmtId result must be consumed before calling it again */
12710                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12711                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12712                 }
12713                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12714                                                   fmtId(provider), target->data);
12715                 appendStringLiteralAH(query, label, fout);
12716                 appendPQExpBufferStr(query, ";\n");
12717         }
12718         if (query->len > 0)
12719         {
12720                 resetPQExpBuffer(target);
12721                 appendPQExpBuffer(target, "%s %s", reltypename,
12722                                                   fmtId(tbinfo->dobj.name));
12723                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12724                                          target->data,
12725                                          tbinfo->dobj.namespace->dobj.name,
12726                                          NULL, tbinfo->rolname,
12727                                          false, "SECURITY LABEL", SECTION_NONE,
12728                                          query->data, "", NULL,
12729                                          &(tbinfo->dobj.dumpId), 1,
12730                                          NULL, NULL);
12731         }
12732         destroyPQExpBuffer(query);
12733         destroyPQExpBuffer(target);
12734 }
12735
12736 /*
12737  * findSecLabels
12738  *
12739  * Find the security label(s), if any, associated with the given object.
12740  * All the objsubid values associated with the given classoid/objoid are
12741  * found with one search.
12742  */
12743 static int
12744 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12745 {
12746         /* static storage for table of security labels */
12747         static SecLabelItem *labels = NULL;
12748         static int      nlabels = -1;
12749
12750         SecLabelItem *middle = NULL;
12751         SecLabelItem *low;
12752         SecLabelItem *high;
12753         int                     nmatch;
12754
12755         /* Get security labels if we didn't already */
12756         if (nlabels < 0)
12757                 nlabels = collectSecLabels(fout, &labels);
12758
12759         if (nlabels <= 0)                       /* no labels, so no match is possible */
12760         {
12761                 *items = NULL;
12762                 return 0;
12763         }
12764
12765         /*
12766          * Do binary search to find some item matching the object.
12767          */
12768         low = &labels[0];
12769         high = &labels[nlabels - 1];
12770         while (low <= high)
12771         {
12772                 middle = low + (high - low) / 2;
12773
12774                 if (classoid < middle->classoid)
12775                         high = middle - 1;
12776                 else if (classoid > middle->classoid)
12777                         low = middle + 1;
12778                 else if (objoid < middle->objoid)
12779                         high = middle - 1;
12780                 else if (objoid > middle->objoid)
12781                         low = middle + 1;
12782                 else
12783                         break;                          /* found a match */
12784         }
12785
12786         if (low > high)                         /* no matches */
12787         {
12788                 *items = NULL;
12789                 return 0;
12790         }
12791
12792         /*
12793          * Now determine how many items match the object.  The search loop
12794          * invariant still holds: only items between low and high inclusive could
12795          * match.
12796          */
12797         nmatch = 1;
12798         while (middle > low)
12799         {
12800                 if (classoid != middle[-1].classoid ||
12801                         objoid != middle[-1].objoid)
12802                         break;
12803                 middle--;
12804                 nmatch++;
12805         }
12806
12807         *items = middle;
12808
12809         middle += nmatch;
12810         while (middle <= high)
12811         {
12812                 if (classoid != middle->classoid ||
12813                         objoid != middle->objoid)
12814                         break;
12815                 middle++;
12816                 nmatch++;
12817         }
12818
12819         return nmatch;
12820 }
12821
12822 /*
12823  * collectSecLabels
12824  *
12825  * Construct a table of all security labels available for database objects.
12826  * It's much faster to pull them all at once.
12827  *
12828  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12829  */
12830 static int
12831 collectSecLabels(Archive *fout, SecLabelItem **items)
12832 {
12833         PGresult   *res;
12834         PQExpBuffer query;
12835         int                     i_label;
12836         int                     i_provider;
12837         int                     i_classoid;
12838         int                     i_objoid;
12839         int                     i_objsubid;
12840         int                     ntups;
12841         int                     i;
12842         SecLabelItem *labels;
12843
12844         query = createPQExpBuffer();
12845
12846         appendPQExpBufferStr(query,
12847                                                  "SELECT label, provider, classoid, objoid, objsubid "
12848                                                  "FROM pg_catalog.pg_seclabel "
12849                                                  "ORDER BY classoid, objoid, objsubid");
12850
12851         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12852
12853         /* Construct lookup table containing OIDs in numeric form */
12854         i_label = PQfnumber(res, "label");
12855         i_provider = PQfnumber(res, "provider");
12856         i_classoid = PQfnumber(res, "classoid");
12857         i_objoid = PQfnumber(res, "objoid");
12858         i_objsubid = PQfnumber(res, "objsubid");
12859
12860         ntups = PQntuples(res);
12861
12862         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12863
12864         for (i = 0; i < ntups; i++)
12865         {
12866                 labels[i].label = PQgetvalue(res, i, i_label);
12867                 labels[i].provider = PQgetvalue(res, i, i_provider);
12868                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12869                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12870                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12871         }
12872
12873         /* Do NOT free the PGresult since we are keeping pointers into it */
12874         destroyPQExpBuffer(query);
12875
12876         *items = labels;
12877         return ntups;
12878 }
12879
12880 /*
12881  * dumpTable
12882  *        write out to fout the declarations (not data) of a user-defined table
12883  */
12884 static void
12885 dumpTable(Archive *fout, TableInfo *tbinfo)
12886 {
12887         if (tbinfo->dobj.dump && !dataOnly)
12888         {
12889                 char       *namecopy;
12890
12891                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12892                         dumpSequence(fout, tbinfo);
12893                 else
12894                         dumpTableSchema(fout, tbinfo);
12895
12896                 /* Handle the ACL here */
12897                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12898                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12899                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12900                                 "TABLE",
12901                                 namecopy, NULL, tbinfo->dobj.name,
12902                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12903                                 tbinfo->relacl);
12904
12905                 /*
12906                  * Handle column ACLs, if any.  Note: we pull these with a separate
12907                  * query rather than trying to fetch them during getTableAttrs, so
12908                  * that we won't miss ACLs on system columns.
12909                  */
12910                 if (fout->remoteVersion >= 80400)
12911                 {
12912                         PQExpBuffer query = createPQExpBuffer();
12913                         PGresult   *res;
12914                         int                     i;
12915
12916                         appendPQExpBuffer(query,
12917                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12918                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12919                                                           "ORDER BY attnum",
12920                                                           tbinfo->dobj.catId.oid);
12921                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12922
12923                         for (i = 0; i < PQntuples(res); i++)
12924                         {
12925                                 char       *attname = PQgetvalue(res, i, 0);
12926                                 char       *attacl = PQgetvalue(res, i, 1);
12927                                 char       *attnamecopy;
12928                                 char       *acltag;
12929
12930                                 attnamecopy = pg_strdup(fmtId(attname));
12931                                 acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
12932                                 /* Column's GRANT type is always TABLE */
12933                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12934                                                 namecopy, attnamecopy, acltag,
12935                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12936                                                 attacl);
12937                                 free(attnamecopy);
12938                                 free(acltag);
12939                         }
12940                         PQclear(res);
12941                         destroyPQExpBuffer(query);
12942                 }
12943
12944                 free(namecopy);
12945         }
12946 }
12947
12948 /*
12949  * Create the AS clause for a view or materialized view. The semicolon is
12950  * stripped because a materialized view must add a WITH NO DATA clause.
12951  *
12952  * This returns a new buffer which must be freed by the caller.
12953  */
12954 static PQExpBuffer
12955 createViewAsClause(Archive *fout, TableInfo *tbinfo)
12956 {
12957         PQExpBuffer query = createPQExpBuffer();
12958         PQExpBuffer result = createPQExpBuffer();
12959         PGresult   *res;
12960         int                     len;
12961
12962         /* Fetch the view definition */
12963         if (fout->remoteVersion >= 70300)
12964         {
12965                 /* Beginning in 7.3, viewname is not unique; rely on OID */
12966                 appendPQExpBuffer(query,
12967                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12968                                                   tbinfo->dobj.catId.oid);
12969         }
12970         else
12971         {
12972                 appendPQExpBufferStr(query, "SELECT definition AS viewdef "
12973                                                          "FROM pg_views WHERE viewname = ");
12974                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12975         }
12976
12977         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12978
12979         if (PQntuples(res) != 1)
12980         {
12981                 if (PQntuples(res) < 1)
12982                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12983                                                   tbinfo->dobj.name);
12984                 else
12985                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12986                                                   tbinfo->dobj.name);
12987         }
12988
12989         len = PQgetlength(res, 0, 0);
12990
12991         if (len == 0)
12992                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12993                                           tbinfo->dobj.name);
12994
12995         /* Strip off the trailing semicolon so that other things may follow. */
12996         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
12997         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
12998
12999         PQclear(res);
13000         destroyPQExpBuffer(query);
13001
13002         return result;
13003 }
13004
13005 /*
13006  * dumpTableSchema
13007  *        write the declaration (not data) of one user-defined table or view
13008  */
13009 static void
13010 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
13011 {
13012         PQExpBuffer q = createPQExpBuffer();
13013         PQExpBuffer delq = createPQExpBuffer();
13014         PQExpBuffer labelq = createPQExpBuffer();
13015         int                     numParents;
13016         TableInfo **parents;
13017         int                     actual_atts;    /* number of attrs in this CREATE statement */
13018         const char *reltypename;
13019         char       *storage;
13020         char       *srvname;
13021         char       *ftoptions;
13022         int                     j,
13023                                 k;
13024
13025         /* Make sure we are in proper schema */
13026         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13027
13028         if (binary_upgrade)
13029                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
13030                                                                                                 tbinfo->dobj.catId.oid);
13031
13032         /* Is it a table or a view? */
13033         if (tbinfo->relkind == RELKIND_VIEW)
13034         {
13035                 PQExpBuffer result;
13036
13037                 reltypename = "VIEW";
13038
13039                 /*
13040                  * DROP must be fully qualified in case same name appears in
13041                  * pg_catalog
13042                  */
13043                 appendPQExpBuffer(delq, "DROP VIEW %s.",
13044                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13045                 appendPQExpBuffer(delq, "%s;\n",
13046                                                   fmtId(tbinfo->dobj.name));
13047
13048                 if (binary_upgrade)
13049                         binary_upgrade_set_pg_class_oids(fout, q,
13050                                                                                          tbinfo->dobj.catId.oid, false);
13051
13052                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
13053                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13054                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
13055                 result = createViewAsClause(fout, tbinfo);
13056                 appendPQExpBuffer(q, " AS\n%s", result->data);
13057                 destroyPQExpBuffer(result);
13058
13059                 if (tbinfo->checkoption != NULL)
13060                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
13061                 appendPQExpBufferStr(q, ";\n");
13062
13063                 appendPQExpBuffer(labelq, "VIEW %s",
13064                                                   fmtId(tbinfo->dobj.name));
13065         }
13066         else
13067         {
13068                 switch (tbinfo->relkind)
13069                 {
13070                         case (RELKIND_FOREIGN_TABLE):
13071                                 {
13072                                         PQExpBuffer query = createPQExpBuffer();
13073                                         PGresult   *res;
13074                                         int                     i_srvname;
13075                                         int                     i_ftoptions;
13076
13077                                         reltypename = "FOREIGN TABLE";
13078
13079                                         /* retrieve name of foreign server and generic options */
13080                                         appendPQExpBuffer(query,
13081                                                                           "SELECT fs.srvname, "
13082                                                                           "pg_catalog.array_to_string(ARRAY("
13083                                                          "SELECT pg_catalog.quote_ident(option_name) || "
13084                                                          "' ' || pg_catalog.quote_literal(option_value) "
13085                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
13086                                                                           "ORDER BY option_name"
13087                                                                           "), E',\n    ') AS ftoptions "
13088                                                                           "FROM pg_catalog.pg_foreign_table ft "
13089                                                                           "JOIN pg_catalog.pg_foreign_server fs "
13090                                                                           "ON (fs.oid = ft.ftserver) "
13091                                                                           "WHERE ft.ftrelid = '%u'",
13092                                                                           tbinfo->dobj.catId.oid);
13093                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13094                                         i_srvname = PQfnumber(res, "srvname");
13095                                         i_ftoptions = PQfnumber(res, "ftoptions");
13096                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
13097                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
13098                                         PQclear(res);
13099                                         destroyPQExpBuffer(query);
13100                                         break;
13101                                 }
13102                         case (RELKIND_MATVIEW):
13103                                 reltypename = "MATERIALIZED VIEW";
13104                                 srvname = NULL;
13105                                 ftoptions = NULL;
13106                                 break;
13107                         default:
13108                                 reltypename = "TABLE";
13109                                 srvname = NULL;
13110                                 ftoptions = NULL;
13111                 }
13112
13113                 numParents = tbinfo->numParents;
13114                 parents = tbinfo->parents;
13115
13116                 /*
13117                  * DROP must be fully qualified in case same name appears in
13118                  * pg_catalog
13119                  */
13120                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
13121                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13122                 appendPQExpBuffer(delq, "%s;\n",
13123                                                   fmtId(tbinfo->dobj.name));
13124
13125                 appendPQExpBuffer(labelq, "%s %s", reltypename,
13126                                                   fmtId(tbinfo->dobj.name));
13127
13128                 if (binary_upgrade)
13129                         binary_upgrade_set_pg_class_oids(fout, q,
13130                                                                                          tbinfo->dobj.catId.oid, false);
13131
13132                 appendPQExpBuffer(q, "CREATE %s%s %s",
13133                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
13134                                                   "UNLOGGED " : "",
13135                                                   reltypename,
13136                                                   fmtId(tbinfo->dobj.name));
13137
13138                 /*
13139                  * Attach to type, if reloftype; except in case of a binary upgrade,
13140                  * we dump the table normally and attach it to the type afterward.
13141                  */
13142                 if (tbinfo->reloftype && !binary_upgrade)
13143                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
13144
13145                 if (tbinfo->relkind != RELKIND_MATVIEW)
13146                 {
13147                         /* Dump the attributes */
13148                         actual_atts = 0;
13149                         for (j = 0; j < tbinfo->numatts; j++)
13150                         {
13151                                 /*
13152                                  * Normally, dump if it's locally defined in this table, and
13153                                  * not dropped.  But for binary upgrade, we'll dump all the
13154                                  * columns, and then fix up the dropped and nonlocal cases
13155                                  * below.
13156                                  */
13157                                 if (shouldPrintColumn(tbinfo, j))
13158                                 {
13159                                         /*
13160                                          * Default value --- suppress if to be printed separately.
13161                                          */
13162                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
13163                                                                                          !tbinfo->attrdefs[j]->separate);
13164
13165                                         /*
13166                                          * Not Null constraint --- suppress if inherited, except
13167                                          * in binary-upgrade case where that won't work.
13168                                          */
13169                                         bool            has_notnull = (tbinfo->notnull[j] &&
13170                                                                                            (!tbinfo->inhNotNull[j] ||
13171                                                                                                 binary_upgrade));
13172
13173                                         /* Skip column if fully defined by reloftype */
13174                                         if (tbinfo->reloftype &&
13175                                                 !has_default && !has_notnull && !binary_upgrade)
13176                                                 continue;
13177
13178                                         /* Format properly if not first attr */
13179                                         if (actual_atts == 0)
13180                                                 appendPQExpBufferStr(q, " (");
13181                                         else
13182                                                 appendPQExpBufferStr(q, ",");
13183                                         appendPQExpBufferStr(q, "\n    ");
13184                                         actual_atts++;
13185
13186                                         /* Attribute name */
13187                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
13188
13189                                         if (tbinfo->attisdropped[j])
13190                                         {
13191                                                 /*
13192                                                  * ALTER TABLE DROP COLUMN clears
13193                                                  * pg_attribute.atttypid, so we will not have gotten a
13194                                                  * valid type name; insert INTEGER as a stopgap. We'll
13195                                                  * clean things up later.
13196                                                  */
13197                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
13198                                                 /* Skip all the rest, too */
13199                                                 continue;
13200                                         }
13201
13202                                         /* Attribute type */
13203                                         if (tbinfo->reloftype && !binary_upgrade)
13204                                         {
13205                                                 appendPQExpBufferStr(q, " WITH OPTIONS");
13206                                         }
13207                                         else if (fout->remoteVersion >= 70100)
13208                                         {
13209                                                 appendPQExpBuffer(q, " %s",
13210                                                                                   tbinfo->atttypnames[j]);
13211                                         }
13212                                         else
13213                                         {
13214                                                 /* If no format_type, fake it */
13215                                                 appendPQExpBuffer(q, " %s",
13216                                                                                   myFormatType(tbinfo->atttypnames[j],
13217                                                                                                            tbinfo->atttypmod[j]));
13218                                         }
13219
13220                                         /* Add collation if not default for the type */
13221                                         if (OidIsValid(tbinfo->attcollation[j]))
13222                                         {
13223                                                 CollInfo   *coll;
13224
13225                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
13226                                                 if (coll)
13227                                                 {
13228                                                         /* always schema-qualify, don't try to be smart */
13229                                                         appendPQExpBuffer(q, " COLLATE %s.",
13230                                                                          fmtId(coll->dobj.namespace->dobj.name));
13231                                                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
13232                                                 }
13233                                         }
13234
13235                                         if (has_default)
13236                                                 appendPQExpBuffer(q, " DEFAULT %s",
13237                                                                                   tbinfo->attrdefs[j]->adef_expr);
13238
13239                                         if (has_notnull)
13240                                                 appendPQExpBufferStr(q, " NOT NULL");
13241                                 }
13242                         }
13243
13244                         /*
13245                          * Add non-inherited CHECK constraints, if any.
13246                          */
13247                         for (j = 0; j < tbinfo->ncheck; j++)
13248                         {
13249                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13250
13251                                 if (constr->separate || !constr->conislocal)
13252                                         continue;
13253
13254                                 if (actual_atts == 0)
13255                                         appendPQExpBufferStr(q, " (\n    ");
13256                                 else
13257                                         appendPQExpBufferStr(q, ",\n    ");
13258
13259                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13260                                                                   fmtId(constr->dobj.name));
13261                                 appendPQExpBufferStr(q, constr->condef);
13262
13263                                 actual_atts++;
13264                         }
13265
13266                         if (actual_atts)
13267                                 appendPQExpBufferStr(q, "\n)");
13268                         else if (!(tbinfo->reloftype && !binary_upgrade))
13269                         {
13270                                 /*
13271                                  * We must have a parenthesized attribute list, even though
13272                                  * empty, when not using the OF TYPE syntax.
13273                                  */
13274                                 appendPQExpBufferStr(q, " (\n)");
13275                         }
13276
13277                         if (numParents > 0 && !binary_upgrade)
13278                         {
13279                                 appendPQExpBufferStr(q, "\nINHERITS (");
13280                                 for (k = 0; k < numParents; k++)
13281                                 {
13282                                         TableInfo  *parentRel = parents[k];
13283
13284                                         if (k > 0)
13285                                                 appendPQExpBufferStr(q, ", ");
13286                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13287                                                 appendPQExpBuffer(q, "%s.",
13288                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13289                                         appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
13290                                 }
13291                                 appendPQExpBufferChar(q, ')');
13292                         }
13293
13294                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13295                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13296                 }
13297
13298                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13299                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13300                 {
13301                         bool            addcomma = false;
13302
13303                         appendPQExpBufferStr(q, "\nWITH (");
13304                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13305                         {
13306                                 addcomma = true;
13307                                 appendPQExpBufferStr(q, tbinfo->reloptions);
13308                         }
13309                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13310                         {
13311                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13312                                                                   tbinfo->toast_reloptions);
13313                         }
13314                         appendPQExpBufferChar(q, ')');
13315                 }
13316
13317                 /* Dump generic options if any */
13318                 if (ftoptions && ftoptions[0])
13319                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13320
13321                 /*
13322                  * For materialized views, create the AS clause just like a view. At
13323                  * this point, we always mark the view as not populated.
13324                  */
13325                 if (tbinfo->relkind == RELKIND_MATVIEW)
13326                 {
13327                         PQExpBuffer result;
13328
13329                         result = createViewAsClause(fout, tbinfo);
13330                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13331                                                           result->data);
13332                         destroyPQExpBuffer(result);
13333                 }
13334                 else
13335                         appendPQExpBufferStr(q, ";\n");
13336
13337                 /*
13338                  * To create binary-compatible heap files, we have to ensure the same
13339                  * physical column order, including dropped columns, as in the
13340                  * original.  Therefore, we create dropped columns above and drop them
13341                  * here, also updating their attlen/attalign values so that the
13342                  * dropped column can be skipped properly.      (We do not bother with
13343                  * restoring the original attbyval setting.)  Also, inheritance
13344                  * relationships are set up by doing ALTER INHERIT rather than using
13345                  * an INHERITS clause --- the latter would possibly mess up the column
13346                  * order.  That also means we have to take care about setting
13347                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13348                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13349                  */
13350                 if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
13351                                                            tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
13352                 {
13353                         for (j = 0; j < tbinfo->numatts; j++)
13354                         {
13355                                 if (tbinfo->attisdropped[j])
13356                                 {
13357                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
13358                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13359                                                                           "SET attlen = %d, "
13360                                                                           "attalign = '%c', attbyval = false\n"
13361                                                                           "WHERE attname = ",
13362                                                                           tbinfo->attlen[j],
13363                                                                           tbinfo->attalign[j]);
13364                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13365                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
13366                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13367                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13368
13369                                         if (tbinfo->relkind == RELKIND_RELATION)
13370                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13371                                                                                   fmtId(tbinfo->dobj.name));
13372                                         else
13373                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13374                                                                                   fmtId(tbinfo->dobj.name));
13375
13376                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13377                                                                           fmtId(tbinfo->attnames[j]));
13378                                 }
13379                                 else if (!tbinfo->attislocal[j])
13380                                 {
13381                                         Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
13382                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
13383                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
13384                                                                           "SET attislocal = false\n"
13385                                                                           "WHERE attname = ");
13386                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13387                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
13388                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13389                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13390                                 }
13391                         }
13392
13393                         for (k = 0; k < tbinfo->ncheck; k++)
13394                         {
13395                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13396
13397                                 if (constr->separate || constr->conislocal)
13398                                         continue;
13399
13400                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13401                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13402                                                                   fmtId(tbinfo->dobj.name));
13403                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13404                                                                   fmtId(constr->dobj.name));
13405                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13406                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
13407                                                                   "SET conislocal = false\n"
13408                                                                   "WHERE contype = 'c' AND conname = ");
13409                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13410                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
13411                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13412                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13413                         }
13414
13415                         if (numParents > 0)
13416                         {
13417                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13418                                 for (k = 0; k < numParents; k++)
13419                                 {
13420                                         TableInfo  *parentRel = parents[k];
13421
13422                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13423                                                                           fmtId(tbinfo->dobj.name));
13424                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13425                                                 appendPQExpBuffer(q, "%s.",
13426                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13427                                         appendPQExpBuffer(q, "%s;\n",
13428                                                                           fmtId(parentRel->dobj.name));
13429                                 }
13430                         }
13431
13432                         if (tbinfo->reloftype)
13433                         {
13434                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13435                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13436                                                                   fmtId(tbinfo->dobj.name),
13437                                                                   tbinfo->reloftype);
13438                         }
13439
13440                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13441                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13442                                                           "SET relfrozenxid = '%u'\n"
13443                                                           "WHERE oid = ",
13444                                                           tbinfo->frozenxid);
13445                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13446                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13447
13448                         if (tbinfo->toast_oid)
13449                         {
13450                                 /* We preserve the toast oids, so we can use it during restore */
13451                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13452                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13453                                                                   "SET relfrozenxid = '%u'\n"
13454                                                                   "WHERE oid = '%u';\n",
13455                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13456                         }
13457                 }
13458
13459                 /*
13460                  * In binary_upgrade mode, restore matviews' populated status by
13461                  * poking pg_class directly.  This is pretty ugly, but we can't use
13462                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
13463                  * matview is not populated even though this matview is.
13464                  */
13465                 if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
13466                         tbinfo->relispopulated)
13467                 {
13468                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
13469                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
13470                                                           "SET relispopulated = 't'\n"
13471                                                           "WHERE oid = ");
13472                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13473                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13474                 }
13475
13476                 /*
13477                  * Dump additional per-column properties that we can't handle in the
13478                  * main CREATE TABLE command.
13479                  */
13480                 for (j = 0; j < tbinfo->numatts; j++)
13481                 {
13482                         /* None of this applies to dropped columns */
13483                         if (tbinfo->attisdropped[j])
13484                                 continue;
13485
13486                         /*
13487                          * If we didn't dump the column definition explicitly above, and
13488                          * it is NOT NULL and did not inherit that property from a parent,
13489                          * we have to mark it separately.
13490                          */
13491                         if (!shouldPrintColumn(tbinfo, j) &&
13492                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13493                         {
13494                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13495                                                                   fmtId(tbinfo->dobj.name));
13496                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13497                                                                   fmtId(tbinfo->attnames[j]));
13498                         }
13499
13500                         /*
13501                          * Dump per-column statistics information. We only issue an ALTER
13502                          * TABLE statement if the attstattarget entry for this column is
13503                          * non-negative (i.e. it's not the default value)
13504                          */
13505                         if (tbinfo->attstattarget[j] >= 0)
13506                         {
13507                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13508                                                                   fmtId(tbinfo->dobj.name));
13509                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13510                                                                   fmtId(tbinfo->attnames[j]));
13511                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13512                                                                   tbinfo->attstattarget[j]);
13513                         }
13514
13515                         /*
13516                          * Dump per-column storage information.  The statement is only
13517                          * dumped if the storage has been changed from the type's default.
13518                          */
13519                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13520                         {
13521                                 switch (tbinfo->attstorage[j])
13522                                 {
13523                                         case 'p':
13524                                                 storage = "PLAIN";
13525                                                 break;
13526                                         case 'e':
13527                                                 storage = "EXTERNAL";
13528                                                 break;
13529                                         case 'm':
13530                                                 storage = "MAIN";
13531                                                 break;
13532                                         case 'x':
13533                                                 storage = "EXTENDED";
13534                                                 break;
13535                                         default:
13536                                                 storage = NULL;
13537                                 }
13538
13539                                 /*
13540                                  * Only dump the statement if it's a storage type we recognize
13541                                  */
13542                                 if (storage != NULL)
13543                                 {
13544                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13545                                                                           fmtId(tbinfo->dobj.name));
13546                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
13547                                                                           fmtId(tbinfo->attnames[j]));
13548                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
13549                                                                           storage);
13550                                 }
13551                         }
13552
13553                         /*
13554                          * Dump per-column attributes.
13555                          */
13556                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13557                         {
13558                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13559                                                                   fmtId(tbinfo->dobj.name));
13560                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13561                                                                   fmtId(tbinfo->attnames[j]));
13562                                 appendPQExpBuffer(q, "SET (%s);\n",
13563                                                                   tbinfo->attoptions[j]);
13564                         }
13565
13566                         /*
13567                          * Dump per-column fdw options.
13568                          */
13569                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13570                                 tbinfo->attfdwoptions[j] &&
13571                                 tbinfo->attfdwoptions[j][0] != '\0')
13572                         {
13573                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13574                                                                   fmtId(tbinfo->dobj.name));
13575                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13576                                                                   fmtId(tbinfo->attnames[j]));
13577                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13578                                                                   tbinfo->attfdwoptions[j]);
13579                         }
13580                 }
13581         }
13582
13583         /*
13584          * dump properties we only have ALTER TABLE syntax for
13585          */
13586         if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) &&
13587                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
13588         {
13589                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
13590                 {
13591                         /* nothing to do, will be set when the index is dumped */
13592                 }
13593                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
13594                 {
13595                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
13596                                                           fmtId(tbinfo->dobj.name));
13597                 }
13598                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
13599                 {
13600                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
13601                                                           fmtId(tbinfo->dobj.name));
13602                 }
13603         }
13604
13605         if (binary_upgrade)
13606                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13607
13608         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13609                                  tbinfo->dobj.name,
13610                                  tbinfo->dobj.namespace->dobj.name,
13611                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13612                                  tbinfo->rolname,
13613                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13614                                  reltypename, SECTION_PRE_DATA,
13615                                  q->data, delq->data, NULL,
13616                                  NULL, 0,
13617                                  NULL, NULL);
13618
13619
13620         /* Dump Table Comments */
13621         dumpTableComment(fout, tbinfo, reltypename);
13622
13623         /* Dump Table Security Labels */
13624         dumpTableSecLabel(fout, tbinfo, reltypename);
13625
13626         /* Dump comments on inlined table constraints */
13627         for (j = 0; j < tbinfo->ncheck; j++)
13628         {
13629                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13630
13631                 if (constr->separate || !constr->conislocal)
13632                         continue;
13633
13634                 dumpTableConstraintComment(fout, constr);
13635         }
13636
13637         destroyPQExpBuffer(q);
13638         destroyPQExpBuffer(delq);
13639         destroyPQExpBuffer(labelq);
13640 }
13641
13642 /*
13643  * dumpAttrDef --- dump an attribute's default-value declaration
13644  */
13645 static void
13646 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13647 {
13648         TableInfo  *tbinfo = adinfo->adtable;
13649         int                     adnum = adinfo->adnum;
13650         PQExpBuffer q;
13651         PQExpBuffer delq;
13652
13653         /* Skip if table definition not to be dumped */
13654         if (!tbinfo->dobj.dump || dataOnly)
13655                 return;
13656
13657         /* Skip if not "separate"; it was dumped in the table's definition */
13658         if (!adinfo->separate)
13659                 return;
13660
13661         q = createPQExpBuffer();
13662         delq = createPQExpBuffer();
13663
13664         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13665                                           fmtId(tbinfo->dobj.name));
13666         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13667                                           fmtId(tbinfo->attnames[adnum - 1]),
13668                                           adinfo->adef_expr);
13669
13670         /*
13671          * DROP must be fully qualified in case same name appears in pg_catalog
13672          */
13673         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13674                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13675         appendPQExpBuffer(delq, "%s ",
13676                                           fmtId(tbinfo->dobj.name));
13677         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13678                                           fmtId(tbinfo->attnames[adnum - 1]));
13679
13680         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13681                                  tbinfo->attnames[adnum - 1],
13682                                  tbinfo->dobj.namespace->dobj.name,
13683                                  NULL,
13684                                  tbinfo->rolname,
13685                                  false, "DEFAULT", SECTION_PRE_DATA,
13686                                  q->data, delq->data, NULL,
13687                                  NULL, 0,
13688                                  NULL, NULL);
13689
13690         destroyPQExpBuffer(q);
13691         destroyPQExpBuffer(delq);
13692 }
13693
13694 /*
13695  * getAttrName: extract the correct name for an attribute
13696  *
13697  * The array tblInfo->attnames[] only provides names of user attributes;
13698  * if a system attribute number is supplied, we have to fake it.
13699  * We also do a little bit of bounds checking for safety's sake.
13700  */
13701 static const char *
13702 getAttrName(int attrnum, TableInfo *tblInfo)
13703 {
13704         if (attrnum > 0 && attrnum <= tblInfo->numatts)
13705                 return tblInfo->attnames[attrnum - 1];
13706         switch (attrnum)
13707         {
13708                 case SelfItemPointerAttributeNumber:
13709                         return "ctid";
13710                 case ObjectIdAttributeNumber:
13711                         return "oid";
13712                 case MinTransactionIdAttributeNumber:
13713                         return "xmin";
13714                 case MinCommandIdAttributeNumber:
13715                         return "cmin";
13716                 case MaxTransactionIdAttributeNumber:
13717                         return "xmax";
13718                 case MaxCommandIdAttributeNumber:
13719                         return "cmax";
13720                 case TableOidAttributeNumber:
13721                         return "tableoid";
13722         }
13723         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13724                                   attrnum, tblInfo->dobj.name);
13725         return NULL;                            /* keep compiler quiet */
13726 }
13727
13728 /*
13729  * dumpIndex
13730  *        write out to fout a user-defined index
13731  */
13732 static void
13733 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13734 {
13735         TableInfo  *tbinfo = indxinfo->indextable;
13736         bool            is_constraint = (indxinfo->indexconstraint != 0);
13737         PQExpBuffer q;
13738         PQExpBuffer delq;
13739         PQExpBuffer labelq;
13740
13741         if (dataOnly)
13742                 return;
13743
13744         q = createPQExpBuffer();
13745         delq = createPQExpBuffer();
13746         labelq = createPQExpBuffer();
13747
13748         appendPQExpBuffer(labelq, "INDEX %s",
13749                                           fmtId(indxinfo->dobj.name));
13750
13751         /*
13752          * If there's an associated constraint, don't dump the index per se, but
13753          * do dump any comment for it.  (This is safe because dependency ordering
13754          * will have ensured the constraint is emitted first.)  Note that the
13755          * emitted comment has to be shown as depending on the constraint, not
13756          * the index, in such cases.
13757          */
13758         if (!is_constraint)
13759         {
13760                 if (binary_upgrade)
13761                         binary_upgrade_set_pg_class_oids(fout, q,
13762                                                                                          indxinfo->dobj.catId.oid, true);
13763
13764                 /* Plain secondary index */
13765                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13766
13767                 /* If the index is clustered, we need to record that. */
13768                 if (indxinfo->indisclustered)
13769                 {
13770                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13771                                                           fmtId(tbinfo->dobj.name));
13772                         appendPQExpBuffer(q, " ON %s;\n",
13773                                                           fmtId(indxinfo->dobj.name));
13774                 }
13775
13776                 /* If the index defines identity, we need to record that. */
13777                 if (indxinfo->indisreplident)
13778                 {
13779                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
13780                                                           fmtId(tbinfo->dobj.name));
13781                         appendPQExpBuffer(q, " INDEX %s;\n",
13782                                                           fmtId(indxinfo->dobj.name));
13783                 }
13784
13785                 /*
13786                  * DROP must be fully qualified in case same name appears in
13787                  * pg_catalog
13788                  */
13789                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13790                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13791                 appendPQExpBuffer(delq, "%s;\n",
13792                                                   fmtId(indxinfo->dobj.name));
13793
13794                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13795                                          indxinfo->dobj.name,
13796                                          tbinfo->dobj.namespace->dobj.name,
13797                                          indxinfo->tablespace,
13798                                          tbinfo->rolname, false,
13799                                          "INDEX", SECTION_POST_DATA,
13800                                          q->data, delq->data, NULL,
13801                                          NULL, 0,
13802                                          NULL, NULL);
13803         }
13804
13805         /* Dump Index Comments */
13806         dumpComment(fout, labelq->data,
13807                                 tbinfo->dobj.namespace->dobj.name,
13808                                 tbinfo->rolname,
13809                                 indxinfo->dobj.catId, 0,
13810                                 is_constraint ? indxinfo->indexconstraint :
13811                                 indxinfo->dobj.dumpId);
13812
13813         destroyPQExpBuffer(q);
13814         destroyPQExpBuffer(delq);
13815         destroyPQExpBuffer(labelq);
13816 }
13817
13818 /*
13819  * dumpConstraint
13820  *        write out to fout a user-defined constraint
13821  */
13822 static void
13823 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13824 {
13825         TableInfo  *tbinfo = coninfo->contable;
13826         PQExpBuffer q;
13827         PQExpBuffer delq;
13828
13829         /* Skip if not to be dumped */
13830         if (!coninfo->dobj.dump || dataOnly)
13831                 return;
13832
13833         q = createPQExpBuffer();
13834         delq = createPQExpBuffer();
13835
13836         if (coninfo->contype == 'p' ||
13837                 coninfo->contype == 'u' ||
13838                 coninfo->contype == 'x')
13839         {
13840                 /* Index-related constraint */
13841                 IndxInfo   *indxinfo;
13842                 int                     k;
13843
13844                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13845
13846                 if (indxinfo == NULL)
13847                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13848                                                   coninfo->dobj.name);
13849
13850                 if (binary_upgrade)
13851                         binary_upgrade_set_pg_class_oids(fout, q,
13852                                                                                          indxinfo->dobj.catId.oid, true);
13853
13854                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13855                                                   fmtId(tbinfo->dobj.name));
13856                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13857                                                   fmtId(coninfo->dobj.name));
13858
13859                 if (coninfo->condef)
13860                 {
13861                         /* pg_get_constraintdef should have provided everything */
13862                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13863                 }
13864                 else
13865                 {
13866                         appendPQExpBuffer(q, "%s (",
13867                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13868                         for (k = 0; k < indxinfo->indnkeys; k++)
13869                         {
13870                                 int                     indkey = (int) indxinfo->indkeys[k];
13871                                 const char *attname;
13872
13873                                 if (indkey == InvalidAttrNumber)
13874                                         break;
13875                                 attname = getAttrName(indkey, tbinfo);
13876
13877                                 appendPQExpBuffer(q, "%s%s",
13878                                                                   (k == 0) ? "" : ", ",
13879                                                                   fmtId(attname));
13880                         }
13881
13882                         appendPQExpBufferChar(q, ')');
13883
13884                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13885                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13886
13887                         if (coninfo->condeferrable)
13888                         {
13889                                 appendPQExpBufferStr(q, " DEFERRABLE");
13890                                 if (coninfo->condeferred)
13891                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
13892                         }
13893
13894                         appendPQExpBufferStr(q, ";\n");
13895                 }
13896
13897                 /* If the index is clustered, we need to record that. */
13898                 if (indxinfo->indisclustered)
13899                 {
13900                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13901                                                           fmtId(tbinfo->dobj.name));
13902                         appendPQExpBuffer(q, " ON %s;\n",
13903                                                           fmtId(indxinfo->dobj.name));
13904                 }
13905
13906                 /*
13907                  * DROP must be fully qualified in case same name appears in
13908                  * pg_catalog
13909                  */
13910                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13911                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13912                 appendPQExpBuffer(delq, "%s ",
13913                                                   fmtId(tbinfo->dobj.name));
13914                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13915                                                   fmtId(coninfo->dobj.name));
13916
13917                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13918                                          coninfo->dobj.name,
13919                                          tbinfo->dobj.namespace->dobj.name,
13920                                          indxinfo->tablespace,
13921                                          tbinfo->rolname, false,
13922                                          "CONSTRAINT", SECTION_POST_DATA,
13923                                          q->data, delq->data, NULL,
13924                                          NULL, 0,
13925                                          NULL, NULL);
13926         }
13927         else if (coninfo->contype == 'f')
13928         {
13929                 /*
13930                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13931                  * current table data is not processed
13932                  */
13933                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13934                                                   fmtId(tbinfo->dobj.name));
13935                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13936                                                   fmtId(coninfo->dobj.name),
13937                                                   coninfo->condef);
13938
13939                 /*
13940                  * DROP must be fully qualified in case same name appears in
13941                  * pg_catalog
13942                  */
13943                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13944                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13945                 appendPQExpBuffer(delq, "%s ",
13946                                                   fmtId(tbinfo->dobj.name));
13947                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13948                                                   fmtId(coninfo->dobj.name));
13949
13950                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13951                                          coninfo->dobj.name,
13952                                          tbinfo->dobj.namespace->dobj.name,
13953                                          NULL,
13954                                          tbinfo->rolname, false,
13955                                          "FK CONSTRAINT", SECTION_POST_DATA,
13956                                          q->data, delq->data, NULL,
13957                                          NULL, 0,
13958                                          NULL, NULL);
13959         }
13960         else if (coninfo->contype == 'c' && tbinfo)
13961         {
13962                 /* CHECK constraint on a table */
13963
13964                 /* Ignore if not to be dumped separately */
13965                 if (coninfo->separate)
13966                 {
13967                         /* not ONLY since we want it to propagate to children */
13968                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13969                                                           fmtId(tbinfo->dobj.name));
13970                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13971                                                           fmtId(coninfo->dobj.name),
13972                                                           coninfo->condef);
13973
13974                         /*
13975                          * DROP must be fully qualified in case same name appears in
13976                          * pg_catalog
13977                          */
13978                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13979                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13980                         appendPQExpBuffer(delq, "%s ",
13981                                                           fmtId(tbinfo->dobj.name));
13982                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13983                                                           fmtId(coninfo->dobj.name));
13984
13985                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13986                                                  coninfo->dobj.name,
13987                                                  tbinfo->dobj.namespace->dobj.name,
13988                                                  NULL,
13989                                                  tbinfo->rolname, false,
13990                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13991                                                  q->data, delq->data, NULL,
13992                                                  NULL, 0,
13993                                                  NULL, NULL);
13994                 }
13995         }
13996         else if (coninfo->contype == 'c' && tbinfo == NULL)
13997         {
13998                 /* CHECK constraint on a domain */
13999                 TypeInfo   *tyinfo = coninfo->condomain;
14000
14001                 /* Ignore if not to be dumped separately */
14002                 if (coninfo->separate)
14003                 {
14004                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
14005                                                           fmtId(tyinfo->dobj.name));
14006                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14007                                                           fmtId(coninfo->dobj.name),
14008                                                           coninfo->condef);
14009
14010                         /*
14011                          * DROP must be fully qualified in case same name appears in
14012                          * pg_catalog
14013                          */
14014                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
14015                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
14016                         appendPQExpBuffer(delq, "%s ",
14017                                                           fmtId(tyinfo->dobj.name));
14018                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14019                                                           fmtId(coninfo->dobj.name));
14020
14021                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14022                                                  coninfo->dobj.name,
14023                                                  tyinfo->dobj.namespace->dobj.name,
14024                                                  NULL,
14025                                                  tyinfo->rolname, false,
14026                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
14027                                                  q->data, delq->data, NULL,
14028                                                  NULL, 0,
14029                                                  NULL, NULL);
14030                 }
14031         }
14032         else
14033         {
14034                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
14035                                           coninfo->contype);
14036         }
14037
14038         /* Dump Constraint Comments --- only works for table constraints */
14039         if (tbinfo && coninfo->separate)
14040                 dumpTableConstraintComment(fout, coninfo);
14041
14042         destroyPQExpBuffer(q);
14043         destroyPQExpBuffer(delq);
14044 }
14045
14046 /*
14047  * dumpTableConstraintComment --- dump a constraint's comment if any
14048  *
14049  * This is split out because we need the function in two different places
14050  * depending on whether the constraint is dumped as part of CREATE TABLE
14051  * or as a separate ALTER command.
14052  */
14053 static void
14054 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
14055 {
14056         TableInfo  *tbinfo = coninfo->contable;
14057         PQExpBuffer labelq = createPQExpBuffer();
14058
14059         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
14060                                           fmtId(coninfo->dobj.name));
14061         appendPQExpBuffer(labelq, "ON %s",
14062                                           fmtId(tbinfo->dobj.name));
14063         dumpComment(fout, labelq->data,
14064                                 tbinfo->dobj.namespace->dobj.name,
14065                                 tbinfo->rolname,
14066                                 coninfo->dobj.catId, 0,
14067                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
14068
14069         destroyPQExpBuffer(labelq);
14070 }
14071
14072 /*
14073  * findLastBuiltInOid -
14074  * find the last built in oid
14075  *
14076  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
14077  * pg_database entry for the current database
14078  */
14079 static Oid
14080 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
14081 {
14082         PGresult   *res;
14083         Oid                     last_oid;
14084         PQExpBuffer query = createPQExpBuffer();
14085
14086         resetPQExpBuffer(query);
14087         appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
14088         appendStringLiteralAH(query, dbname, fout);
14089
14090         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14091         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
14092         PQclear(res);
14093         destroyPQExpBuffer(query);
14094         return last_oid;
14095 }
14096
14097 /*
14098  * findLastBuiltInOid -
14099  * find the last built in oid
14100  *
14101  * For 7.0, we do this by assuming that the last thing that initdb does is to
14102  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
14103  * initdb won't be changing anymore, it'll do.
14104  */
14105 static Oid
14106 findLastBuiltinOid_V70(Archive *fout)
14107 {
14108         PGresult   *res;
14109         int                     last_oid;
14110
14111         res = ExecuteSqlQueryForSingleRow(fout,
14112                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
14113         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
14114         PQclear(res);
14115         return last_oid;
14116 }
14117
14118 /*
14119  * dumpSequence
14120  *        write the declaration (not data) of one user-defined sequence
14121  */
14122 static void
14123 dumpSequence(Archive *fout, TableInfo *tbinfo)
14124 {
14125         PGresult   *res;
14126         char       *startv,
14127                            *incby,
14128                            *maxv = NULL,
14129                            *minv = NULL,
14130                            *cache;
14131         char            bufm[100],
14132                                 bufx[100];
14133         bool            cycled;
14134         PQExpBuffer query = createPQExpBuffer();
14135         PQExpBuffer delqry = createPQExpBuffer();
14136         PQExpBuffer labelq = createPQExpBuffer();
14137
14138         /* Make sure we are in proper schema */
14139         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14140
14141         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
14142         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
14143
14144         if (fout->remoteVersion >= 80400)
14145         {
14146                 appendPQExpBuffer(query,
14147                                                   "SELECT sequence_name, "
14148                                                   "start_value, increment_by, "
14149                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14150                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14151                                                   "     ELSE max_value "
14152                                                   "END AS max_value, "
14153                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14154                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14155                                                   "     ELSE min_value "
14156                                                   "END AS min_value, "
14157                                                   "cache_value, is_cycled FROM %s",
14158                                                   bufx, bufm,
14159                                                   fmtId(tbinfo->dobj.name));
14160         }
14161         else
14162         {
14163                 appendPQExpBuffer(query,
14164                                                   "SELECT sequence_name, "
14165                                                   "0 AS start_value, increment_by, "
14166                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14167                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14168                                                   "     ELSE max_value "
14169                                                   "END AS max_value, "
14170                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14171                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14172                                                   "     ELSE min_value "
14173                                                   "END AS min_value, "
14174                                                   "cache_value, is_cycled FROM %s",
14175                                                   bufx, bufm,
14176                                                   fmtId(tbinfo->dobj.name));
14177         }
14178
14179         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14180
14181         if (PQntuples(res) != 1)
14182         {
14183                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14184                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14185                                                                  PQntuples(res)),
14186                                   tbinfo->dobj.name, PQntuples(res));
14187                 exit_nicely(1);
14188         }
14189
14190         /* Disable this check: it fails if sequence has been renamed */
14191 #ifdef NOT_USED
14192         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
14193         {
14194                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
14195                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
14196                 exit_nicely(1);
14197         }
14198 #endif
14199
14200         startv = PQgetvalue(res, 0, 1);
14201         incby = PQgetvalue(res, 0, 2);
14202         if (!PQgetisnull(res, 0, 3))
14203                 maxv = PQgetvalue(res, 0, 3);
14204         if (!PQgetisnull(res, 0, 4))
14205                 minv = PQgetvalue(res, 0, 4);
14206         cache = PQgetvalue(res, 0, 5);
14207         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
14208
14209         /*
14210          * DROP must be fully qualified in case same name appears in pg_catalog
14211          */
14212         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
14213                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14214         appendPQExpBuffer(delqry, "%s;\n",
14215                                           fmtId(tbinfo->dobj.name));
14216
14217         resetPQExpBuffer(query);
14218
14219         if (binary_upgrade)
14220         {
14221                 binary_upgrade_set_pg_class_oids(fout, query,
14222                                                                                  tbinfo->dobj.catId.oid, false);
14223                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
14224                                                                                                 tbinfo->dobj.catId.oid);
14225         }
14226
14227         appendPQExpBuffer(query,
14228                                           "CREATE SEQUENCE %s\n",
14229                                           fmtId(tbinfo->dobj.name));
14230
14231         if (fout->remoteVersion >= 80400)
14232                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
14233
14234         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
14235
14236         if (minv)
14237                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
14238         else
14239                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
14240
14241         if (maxv)
14242                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
14243         else
14244                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
14245
14246         appendPQExpBuffer(query,
14247                                           "    CACHE %s%s",
14248                                           cache, (cycled ? "\n    CYCLE" : ""));
14249
14250         appendPQExpBufferStr(query, ";\n");
14251
14252         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
14253
14254         /* binary_upgrade:      no need to clear TOAST table oid */
14255
14256         if (binary_upgrade)
14257                 binary_upgrade_extension_member(query, &tbinfo->dobj,
14258                                                                                 labelq->data);
14259
14260         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14261                                  tbinfo->dobj.name,
14262                                  tbinfo->dobj.namespace->dobj.name,
14263                                  NULL,
14264                                  tbinfo->rolname,
14265                                  false, "SEQUENCE", SECTION_PRE_DATA,
14266                                  query->data, delqry->data, NULL,
14267                                  NULL, 0,
14268                                  NULL, NULL);
14269
14270         /*
14271          * If the sequence is owned by a table column, emit the ALTER for it as a
14272          * separate TOC entry immediately following the sequence's own entry. It's
14273          * OK to do this rather than using full sorting logic, because the
14274          * dependency that tells us it's owned will have forced the table to be
14275          * created first.  We can't just include the ALTER in the TOC entry
14276          * because it will fail if we haven't reassigned the sequence owner to
14277          * match the table's owner.
14278          *
14279          * We need not schema-qualify the table reference because both sequence
14280          * and table must be in the same schema.
14281          */
14282         if (OidIsValid(tbinfo->owning_tab))
14283         {
14284                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14285
14286                 if (owning_tab && owning_tab->dobj.dump)
14287                 {
14288                         resetPQExpBuffer(query);
14289                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14290                                                           fmtId(tbinfo->dobj.name));
14291                         appendPQExpBuffer(query, " OWNED BY %s",
14292                                                           fmtId(owning_tab->dobj.name));
14293                         appendPQExpBuffer(query, ".%s;\n",
14294                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14295
14296                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14297                                                  tbinfo->dobj.name,
14298                                                  tbinfo->dobj.namespace->dobj.name,
14299                                                  NULL,
14300                                                  tbinfo->rolname,
14301                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14302                                                  query->data, "", NULL,
14303                                                  &(tbinfo->dobj.dumpId), 1,
14304                                                  NULL, NULL);
14305                 }
14306         }
14307
14308         /* Dump Sequence Comments and Security Labels */
14309         dumpComment(fout, labelq->data,
14310                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14311                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14312         dumpSecLabel(fout, labelq->data,
14313                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14314                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14315
14316         PQclear(res);
14317
14318         destroyPQExpBuffer(query);
14319         destroyPQExpBuffer(delqry);
14320         destroyPQExpBuffer(labelq);
14321 }
14322
14323 /*
14324  * dumpSequenceData
14325  *        write the data of one user-defined sequence
14326  */
14327 static void
14328 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14329 {
14330         TableInfo  *tbinfo = tdinfo->tdtable;
14331         PGresult   *res;
14332         char       *last;
14333         bool            called;
14334         PQExpBuffer query = createPQExpBuffer();
14335
14336         /* Make sure we are in proper schema */
14337         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14338
14339         appendPQExpBuffer(query,
14340                                           "SELECT last_value, is_called FROM %s",
14341                                           fmtId(tbinfo->dobj.name));
14342
14343         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14344
14345         if (PQntuples(res) != 1)
14346         {
14347                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14348                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14349                                                                  PQntuples(res)),
14350                                   tbinfo->dobj.name, PQntuples(res));
14351                 exit_nicely(1);
14352         }
14353
14354         last = PQgetvalue(res, 0, 0);
14355         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14356
14357         resetPQExpBuffer(query);
14358         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
14359         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14360         appendPQExpBuffer(query, ", %s, %s);\n",
14361                                           last, (called ? "true" : "false"));
14362
14363         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14364                                  tbinfo->dobj.name,
14365                                  tbinfo->dobj.namespace->dobj.name,
14366                                  NULL,
14367                                  tbinfo->rolname,
14368                                  false, "SEQUENCE SET", SECTION_DATA,
14369                                  query->data, "", NULL,
14370                                  &(tbinfo->dobj.dumpId), 1,
14371                                  NULL, NULL);
14372
14373         PQclear(res);
14374
14375         destroyPQExpBuffer(query);
14376 }
14377
14378 /*
14379  * dumpTrigger
14380  *        write the declaration of one user-defined table trigger
14381  */
14382 static void
14383 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14384 {
14385         TableInfo  *tbinfo = tginfo->tgtable;
14386         PQExpBuffer query;
14387         PQExpBuffer delqry;
14388         PQExpBuffer labelq;
14389         char       *tgargs;
14390         size_t          lentgargs;
14391         const char *p;
14392         int                     findx;
14393
14394         /*
14395          * we needn't check dobj.dump because TriggerInfo wouldn't have been
14396          * created in the first place for non-dumpable triggers
14397          */
14398         if (dataOnly)
14399                 return;
14400
14401         query = createPQExpBuffer();
14402         delqry = createPQExpBuffer();
14403         labelq = createPQExpBuffer();
14404
14405         /*
14406          * DROP must be fully qualified in case same name appears in pg_catalog
14407          */
14408         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14409                                           fmtId(tginfo->dobj.name));
14410         appendPQExpBuffer(delqry, "ON %s.",
14411                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14412         appendPQExpBuffer(delqry, "%s;\n",
14413                                           fmtId(tbinfo->dobj.name));
14414
14415         if (tginfo->tgdef)
14416         {
14417                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14418         }
14419         else
14420         {
14421                 if (tginfo->tgisconstraint)
14422                 {
14423                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
14424                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14425                 }
14426                 else
14427                 {
14428                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
14429                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14430                 }
14431                 appendPQExpBufferStr(query, "\n    ");
14432
14433                 /* Trigger type */
14434                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14435                         appendPQExpBufferStr(query, "BEFORE");
14436                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14437                         appendPQExpBufferStr(query, "AFTER");
14438                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14439                         appendPQExpBufferStr(query, "INSTEAD OF");
14440                 else
14441                 {
14442                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14443                         exit_nicely(1);
14444                 }
14445
14446                 findx = 0;
14447                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14448                 {
14449                         appendPQExpBufferStr(query, " INSERT");
14450                         findx++;
14451                 }
14452                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14453                 {
14454                         if (findx > 0)
14455                                 appendPQExpBufferStr(query, " OR DELETE");
14456                         else
14457                                 appendPQExpBufferStr(query, " DELETE");
14458                         findx++;
14459                 }
14460                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14461                 {
14462                         if (findx > 0)
14463                                 appendPQExpBufferStr(query, " OR UPDATE");
14464                         else
14465                                 appendPQExpBufferStr(query, " UPDATE");
14466                         findx++;
14467                 }
14468                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14469                 {
14470                         if (findx > 0)
14471                                 appendPQExpBufferStr(query, " OR TRUNCATE");
14472                         else
14473                                 appendPQExpBufferStr(query, " TRUNCATE");
14474                         findx++;
14475                 }
14476                 appendPQExpBuffer(query, " ON %s\n",
14477                                                   fmtId(tbinfo->dobj.name));
14478
14479                 if (tginfo->tgisconstraint)
14480                 {
14481                         if (OidIsValid(tginfo->tgconstrrelid))
14482                         {
14483                                 /* If we are using regclass, name is already quoted */
14484                                 if (fout->remoteVersion >= 70300)
14485                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14486                                                                           tginfo->tgconstrrelname);
14487                                 else
14488                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14489                                                                           fmtId(tginfo->tgconstrrelname));
14490                         }
14491                         if (!tginfo->tgdeferrable)
14492                                 appendPQExpBufferStr(query, "NOT ");
14493                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
14494                         if (tginfo->tginitdeferred)
14495                                 appendPQExpBufferStr(query, "DEFERRED\n");
14496                         else
14497                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
14498                 }
14499
14500                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14501                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
14502                 else
14503                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
14504
14505                 /* In 7.3, result of regproc is already quoted */
14506                 if (fout->remoteVersion >= 70300)
14507                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14508                                                           tginfo->tgfname);
14509                 else
14510                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14511                                                           fmtId(tginfo->tgfname));
14512
14513                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14514                                                                                   &lentgargs);
14515                 p = tgargs;
14516                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14517                 {
14518                         /* find the embedded null that terminates this trigger argument */
14519                         size_t          tlen = strlen(p);
14520
14521                         if (p + tlen >= tgargs + lentgargs)
14522                         {
14523                                 /* hm, not found before end of bytea value... */
14524                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14525                                                   tginfo->tgargs,
14526                                                   tginfo->dobj.name,
14527                                                   tbinfo->dobj.name);
14528                                 exit_nicely(1);
14529                         }
14530
14531                         if (findx > 0)
14532                                 appendPQExpBufferStr(query, ", ");
14533                         appendStringLiteralAH(query, p, fout);
14534                         p += tlen + 1;
14535                 }
14536                 free(tgargs);
14537                 appendPQExpBufferStr(query, ");\n");
14538         }
14539
14540         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14541         {
14542                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
14543                                                   fmtId(tbinfo->dobj.name));
14544                 switch (tginfo->tgenabled)
14545                 {
14546                         case 'D':
14547                         case 'f':
14548                                 appendPQExpBufferStr(query, "DISABLE");
14549                                 break;
14550                         case 'A':
14551                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
14552                                 break;
14553                         case 'R':
14554                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
14555                                 break;
14556                         default:
14557                                 appendPQExpBufferStr(query, "ENABLE");
14558                                 break;
14559                 }
14560                 appendPQExpBuffer(query, " TRIGGER %s;\n",
14561                                                   fmtId(tginfo->dobj.name));
14562         }
14563
14564         appendPQExpBuffer(labelq, "TRIGGER %s ",
14565                                           fmtId(tginfo->dobj.name));
14566         appendPQExpBuffer(labelq, "ON %s",
14567                                           fmtId(tbinfo->dobj.name));
14568
14569         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14570                                  tginfo->dobj.name,
14571                                  tbinfo->dobj.namespace->dobj.name,
14572                                  NULL,
14573                                  tbinfo->rolname, false,
14574                                  "TRIGGER", SECTION_POST_DATA,
14575                                  query->data, delqry->data, NULL,
14576                                  NULL, 0,
14577                                  NULL, NULL);
14578
14579         dumpComment(fout, labelq->data,
14580                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14581                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14582
14583         destroyPQExpBuffer(query);
14584         destroyPQExpBuffer(delqry);
14585         destroyPQExpBuffer(labelq);
14586 }
14587
14588 /*
14589  * dumpEventTrigger
14590  *        write the declaration of one user-defined event trigger
14591  */
14592 static void
14593 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14594 {
14595         PQExpBuffer query;
14596         PQExpBuffer labelq;
14597
14598         /* Skip if not to be dumped */
14599         if (!evtinfo->dobj.dump || dataOnly)
14600                 return;
14601
14602         query = createPQExpBuffer();
14603         labelq = createPQExpBuffer();
14604
14605         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
14606         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14607         appendPQExpBufferStr(query, " ON ");
14608         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14609         appendPQExpBufferStr(query, " ");
14610
14611         if (strcmp("", evtinfo->evttags) != 0)
14612         {
14613                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14614                 appendPQExpBufferStr(query, evtinfo->evttags);
14615                 appendPQExpBufferStr(query, ") ");
14616         }
14617
14618         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
14619         appendPQExpBufferStr(query, evtinfo->evtfname);
14620         appendPQExpBufferStr(query, "();\n");
14621
14622         if (evtinfo->evtenabled != 'O')
14623         {
14624                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14625                                                   fmtId(evtinfo->dobj.name));
14626                 switch (evtinfo->evtenabled)
14627                 {
14628                         case 'D':
14629                                 appendPQExpBufferStr(query, "DISABLE");
14630                                 break;
14631                         case 'A':
14632                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
14633                                 break;
14634                         case 'R':
14635                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
14636                                 break;
14637                         default:
14638                                 appendPQExpBufferStr(query, "ENABLE");
14639                                 break;
14640                 }
14641                 appendPQExpBufferStr(query, ";\n");
14642         }
14643         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14644                                           fmtId(evtinfo->dobj.name));
14645
14646         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14647                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14648                                  "EVENT TRIGGER", SECTION_POST_DATA,
14649                                  query->data, "", NULL, NULL, 0, NULL, NULL);
14650
14651         dumpComment(fout, labelq->data,
14652                                 NULL, NULL,
14653                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14654
14655         destroyPQExpBuffer(query);
14656         destroyPQExpBuffer(labelq);
14657 }
14658
14659 /*
14660  * dumpRule
14661  *              Dump a rule
14662  */
14663 static void
14664 dumpRule(Archive *fout, RuleInfo *rinfo)
14665 {
14666         TableInfo  *tbinfo = rinfo->ruletable;
14667         PQExpBuffer query;
14668         PQExpBuffer cmd;
14669         PQExpBuffer delcmd;
14670         PQExpBuffer labelq;
14671         PGresult   *res;
14672
14673         /* Skip if not to be dumped */
14674         if (!rinfo->dobj.dump || dataOnly)
14675                 return;
14676
14677         /*
14678          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14679          * we do not want to dump it as a separate object.
14680          */
14681         if (!rinfo->separate)
14682                 return;
14683
14684         /*
14685          * Make sure we are in proper schema.
14686          */
14687         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14688
14689         query = createPQExpBuffer();
14690         cmd = createPQExpBuffer();
14691         delcmd = createPQExpBuffer();
14692         labelq = createPQExpBuffer();
14693
14694         if (fout->remoteVersion >= 70300)
14695         {
14696                 appendPQExpBuffer(query,
14697                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14698                                                   rinfo->dobj.catId.oid);
14699         }
14700         else
14701         {
14702                 /* Rule name was unique before 7.3 ... */
14703                 appendPQExpBuffer(query,
14704                                                   "SELECT pg_get_ruledef('%s') AS definition",
14705                                                   rinfo->dobj.name);
14706         }
14707
14708         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14709
14710         if (PQntuples(res) != 1)
14711         {
14712                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14713                                   rinfo->dobj.name, tbinfo->dobj.name);
14714                 exit_nicely(1);
14715         }
14716
14717         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14718
14719         /*
14720          * Add the command to alter the rules replication firing semantics if it
14721          * differs from the default.
14722          */
14723         if (rinfo->ev_enabled != 'O')
14724         {
14725                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14726                 switch (rinfo->ev_enabled)
14727                 {
14728                         case 'A':
14729                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14730                                                                   fmtId(rinfo->dobj.name));
14731                                 break;
14732                         case 'R':
14733                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14734                                                                   fmtId(rinfo->dobj.name));
14735                                 break;
14736                         case 'D':
14737                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14738                                                                   fmtId(rinfo->dobj.name));
14739                                 break;
14740                 }
14741         }
14742
14743         /*
14744          * Apply view's reloptions when its ON SELECT rule is separate.
14745          */
14746         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14747         {
14748                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14749                                                   fmtId(tbinfo->dobj.name),
14750                                                   rinfo->reloptions);
14751         }
14752
14753         /*
14754          * DROP must be fully qualified in case same name appears in pg_catalog
14755          */
14756         appendPQExpBuffer(delcmd, "DROP RULE %s ",
14757                                           fmtId(rinfo->dobj.name));
14758         appendPQExpBuffer(delcmd, "ON %s.",
14759                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14760         appendPQExpBuffer(delcmd, "%s;\n",
14761                                           fmtId(tbinfo->dobj.name));
14762
14763         appendPQExpBuffer(labelq, "RULE %s",
14764                                           fmtId(rinfo->dobj.name));
14765         appendPQExpBuffer(labelq, " ON %s",
14766                                           fmtId(tbinfo->dobj.name));
14767
14768         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14769                                  rinfo->dobj.name,
14770                                  tbinfo->dobj.namespace->dobj.name,
14771                                  NULL,
14772                                  tbinfo->rolname, false,
14773                                  "RULE", SECTION_POST_DATA,
14774                                  cmd->data, delcmd->data, NULL,
14775                                  NULL, 0,
14776                                  NULL, NULL);
14777
14778         /* Dump rule comments */
14779         dumpComment(fout, labelq->data,
14780                                 tbinfo->dobj.namespace->dobj.name,
14781                                 tbinfo->rolname,
14782                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14783
14784         PQclear(res);
14785
14786         destroyPQExpBuffer(query);
14787         destroyPQExpBuffer(cmd);
14788         destroyPQExpBuffer(delcmd);
14789         destroyPQExpBuffer(labelq);
14790 }
14791
14792 /*
14793  * getExtensionMembership --- obtain extension membership data
14794  */
14795 void
14796 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14797                                            int numExtensions)
14798 {
14799         PQExpBuffer query;
14800         PGresult   *res;
14801         int                     ntups,
14802                                 i;
14803         int                     i_classid,
14804                                 i_objid,
14805                                 i_refclassid,
14806                                 i_refobjid;
14807         DumpableObject *dobj,
14808                            *refdobj;
14809
14810         /* Nothing to do if no extensions */
14811         if (numExtensions == 0)
14812                 return;
14813
14814         /* Make sure we are in proper schema */
14815         selectSourceSchema(fout, "pg_catalog");
14816
14817         query = createPQExpBuffer();
14818
14819         /* refclassid constraint is redundant but may speed the search */
14820         appendPQExpBufferStr(query, "SELECT "
14821                                                  "classid, objid, refclassid, refobjid "
14822                                                  "FROM pg_depend "
14823                                                  "WHERE refclassid = 'pg_extension'::regclass "
14824                                                  "AND deptype = 'e' "
14825                                                  "ORDER BY 3,4");
14826
14827         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14828
14829         ntups = PQntuples(res);
14830
14831         i_classid = PQfnumber(res, "classid");
14832         i_objid = PQfnumber(res, "objid");
14833         i_refclassid = PQfnumber(res, "refclassid");
14834         i_refobjid = PQfnumber(res, "refobjid");
14835
14836         /*
14837          * Since we ordered the SELECT by referenced ID, we can expect that
14838          * multiple entries for the same extension will appear together; this
14839          * saves on searches.
14840          */
14841         refdobj = NULL;
14842
14843         for (i = 0; i < ntups; i++)
14844         {
14845                 CatalogId       objId;
14846                 CatalogId       refobjId;
14847
14848                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14849                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14850                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14851                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14852
14853                 if (refdobj == NULL ||
14854                         refdobj->catId.tableoid != refobjId.tableoid ||
14855                         refdobj->catId.oid != refobjId.oid)
14856                         refdobj = findObjectByCatalogId(refobjId);
14857
14858                 /*
14859                  * Failure to find objects mentioned in pg_depend is not unexpected,
14860                  * since for example we don't collect info about TOAST tables.
14861                  */
14862                 if (refdobj == NULL)
14863                 {
14864 #ifdef NOT_USED
14865                         fprintf(stderr, "no referenced object %u %u\n",
14866                                         refobjId.tableoid, refobjId.oid);
14867 #endif
14868                         continue;
14869                 }
14870
14871                 dobj = findObjectByCatalogId(objId);
14872
14873                 if (dobj == NULL)
14874                 {
14875 #ifdef NOT_USED
14876                         fprintf(stderr, "no referencing object %u %u\n",
14877                                         objId.tableoid, objId.oid);
14878 #endif
14879                         continue;
14880                 }
14881
14882                 /* Record dependency so that getDependencies needn't repeat this */
14883                 addObjectDependency(dobj, refdobj->dumpId);
14884
14885                 dobj->ext_member = true;
14886
14887                 /*
14888                  * Normally, mark the member object as not to be dumped.  But in
14889                  * binary upgrades, we still dump the members individually, since the
14890                  * idea is to exactly reproduce the database contents rather than
14891                  * replace the extension contents with something different.
14892                  */
14893                 if (!binary_upgrade)
14894                         dobj->dump = false;
14895                 else
14896                         dobj->dump = refdobj->dump;
14897         }
14898
14899         PQclear(res);
14900
14901         /*
14902          * Now identify extension configuration tables and create TableDataInfo
14903          * objects for them, ensuring their data will be dumped even though the
14904          * tables themselves won't be.
14905          *
14906          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14907          * user data in a configuration table is treated like schema data. This
14908          * seems appropriate since system data in a config table would get
14909          * reloaded by CREATE EXTENSION.
14910          */
14911         for (i = 0; i < numExtensions; i++)
14912         {
14913                 ExtensionInfo *curext = &(extinfo[i]);
14914                 char       *extconfig = curext->extconfig;
14915                 char       *extcondition = curext->extcondition;
14916                 char      **extconfigarray = NULL;
14917                 char      **extconditionarray = NULL;
14918                 int                     nconfigitems;
14919                 int                     nconditionitems;
14920
14921                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14922                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14923                         nconfigitems == nconditionitems)
14924                 {
14925                         int                     j;
14926
14927                         for (j = 0; j < nconfigitems; j++)
14928                         {
14929                                 TableInfo  *configtbl;
14930                                 Oid                     configtbloid = atooid(extconfigarray[j]);
14931                                 bool            dumpobj = curext->dobj.dump;
14932
14933                                 configtbl = findTableByOid(configtbloid);
14934                                 if (configtbl == NULL)
14935                                         continue;
14936
14937                                 /*
14938                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
14939                                  * unless the table or its schema is explicitly included
14940                                  */
14941                                 if (!curext->dobj.dump)
14942                                 {
14943                                         /* check table explicitly requested */
14944                                         if (table_include_oids.head != NULL &&
14945                                                 simple_oid_list_member(&table_include_oids,
14946                                                                                            configtbloid))
14947                                                 dumpobj = true;
14948
14949                                         /* check table's schema explicitly requested */
14950                                         if (configtbl->dobj.namespace->dobj.dump)
14951                                                 dumpobj = true;
14952                                 }
14953
14954                                 /* check table excluded by an exclusion switch */
14955                                 if (table_exclude_oids.head != NULL &&
14956                                         simple_oid_list_member(&table_exclude_oids,
14957                                                                                    configtbloid))
14958                                         dumpobj = false;
14959
14960                                 /* check schema excluded by an exclusion switch */
14961                                 if (simple_oid_list_member(&schema_exclude_oids,
14962                                                                   configtbl->dobj.namespace->dobj.catId.oid))
14963                                         dumpobj = false;
14964
14965                                 if (dumpobj)
14966                                 {
14967                                         /*
14968                                          * Note: config tables are dumped without OIDs regardless
14969                                          * of the --oids setting.  This is because row filtering
14970                                          * conditions aren't compatible with dumping OIDs.
14971                                          */
14972                                         makeTableDataInfo(configtbl, false);
14973                                         if (configtbl->dataObj != NULL)
14974                                         {
14975                                                 if (strlen(extconditionarray[j]) > 0)
14976                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14977                                         }
14978                                 }
14979                         }
14980                 }
14981                 if (extconfigarray)
14982                         free(extconfigarray);
14983                 if (extconditionarray)
14984                         free(extconditionarray);
14985         }
14986
14987         destroyPQExpBuffer(query);
14988 }
14989
14990 /*
14991  * getDependencies --- obtain available dependency data
14992  */
14993 static void
14994 getDependencies(Archive *fout)
14995 {
14996         PQExpBuffer query;
14997         PGresult   *res;
14998         int                     ntups,
14999                                 i;
15000         int                     i_classid,
15001                                 i_objid,
15002                                 i_refclassid,
15003                                 i_refobjid,
15004                                 i_deptype;
15005         DumpableObject *dobj,
15006                            *refdobj;
15007
15008         /* No dependency info available before 7.3 */
15009         if (fout->remoteVersion < 70300)
15010                 return;
15011
15012         if (g_verbose)
15013                 write_msg(NULL, "reading dependency data\n");
15014
15015         /* Make sure we are in proper schema */
15016         selectSourceSchema(fout, "pg_catalog");
15017
15018         query = createPQExpBuffer();
15019
15020         /*
15021          * PIN dependencies aren't interesting, and EXTENSION dependencies were
15022          * already processed by getExtensionMembership.
15023          */
15024         appendPQExpBufferStr(query, "SELECT "
15025                                                  "classid, objid, refclassid, refobjid, deptype "
15026                                                  "FROM pg_depend "
15027                                                  "WHERE deptype != 'p' AND deptype != 'e' "
15028                                                  "ORDER BY 1,2");
15029
15030         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15031
15032         ntups = PQntuples(res);
15033
15034         i_classid = PQfnumber(res, "classid");
15035         i_objid = PQfnumber(res, "objid");
15036         i_refclassid = PQfnumber(res, "refclassid");
15037         i_refobjid = PQfnumber(res, "refobjid");
15038         i_deptype = PQfnumber(res, "deptype");
15039
15040         /*
15041          * Since we ordered the SELECT by referencing ID, we can expect that
15042          * multiple entries for the same object will appear together; this saves
15043          * on searches.
15044          */
15045         dobj = NULL;
15046
15047         for (i = 0; i < ntups; i++)
15048         {
15049                 CatalogId       objId;
15050                 CatalogId       refobjId;
15051                 char            deptype;
15052
15053                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
15054                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
15055                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
15056                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
15057                 deptype = *(PQgetvalue(res, i, i_deptype));
15058
15059                 if (dobj == NULL ||
15060                         dobj->catId.tableoid != objId.tableoid ||
15061                         dobj->catId.oid != objId.oid)
15062                         dobj = findObjectByCatalogId(objId);
15063
15064                 /*
15065                  * Failure to find objects mentioned in pg_depend is not unexpected,
15066                  * since for example we don't collect info about TOAST tables.
15067                  */
15068                 if (dobj == NULL)
15069                 {
15070 #ifdef NOT_USED
15071                         fprintf(stderr, "no referencing object %u %u\n",
15072                                         objId.tableoid, objId.oid);
15073 #endif
15074                         continue;
15075                 }
15076
15077                 refdobj = findObjectByCatalogId(refobjId);
15078
15079                 if (refdobj == NULL)
15080                 {
15081 #ifdef NOT_USED
15082                         fprintf(stderr, "no referenced object %u %u\n",
15083                                         refobjId.tableoid, refobjId.oid);
15084 #endif
15085                         continue;
15086                 }
15087
15088                 /*
15089                  * Ordinarily, table rowtypes have implicit dependencies on their
15090                  * tables.      However, for a composite type the implicit dependency goes
15091                  * the other way in pg_depend; which is the right thing for DROP but
15092                  * it doesn't produce the dependency ordering we need. So in that one
15093                  * case, we reverse the direction of the dependency.
15094                  */
15095                 if (deptype == 'i' &&
15096                         dobj->objType == DO_TABLE &&
15097                         refdobj->objType == DO_TYPE)
15098                         addObjectDependency(refdobj, dobj->dumpId);
15099                 else
15100                         /* normal case */
15101                         addObjectDependency(dobj, refdobj->dumpId);
15102         }
15103
15104         PQclear(res);
15105
15106         destroyPQExpBuffer(query);
15107 }
15108
15109
15110 /*
15111  * createBoundaryObjects - create dummy DumpableObjects to represent
15112  * dump section boundaries.
15113  */
15114 static DumpableObject *
15115 createBoundaryObjects(void)
15116 {
15117         DumpableObject *dobjs;
15118
15119         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
15120
15121         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
15122         dobjs[0].catId = nilCatalogId;
15123         AssignDumpId(dobjs + 0);
15124         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
15125
15126         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
15127         dobjs[1].catId = nilCatalogId;
15128         AssignDumpId(dobjs + 1);
15129         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
15130
15131         return dobjs;
15132 }
15133
15134 /*
15135  * addBoundaryDependencies - add dependencies as needed to enforce the dump
15136  * section boundaries.
15137  */
15138 static void
15139 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
15140                                                 DumpableObject *boundaryObjs)
15141 {
15142         DumpableObject *preDataBound = boundaryObjs + 0;
15143         DumpableObject *postDataBound = boundaryObjs + 1;
15144         int                     i;
15145
15146         for (i = 0; i < numObjs; i++)
15147         {
15148                 DumpableObject *dobj = dobjs[i];
15149
15150                 /*
15151                  * The classification of object types here must match the SECTION_xxx
15152                  * values assigned during subsequent ArchiveEntry calls!
15153                  */
15154                 switch (dobj->objType)
15155                 {
15156                         case DO_NAMESPACE:
15157                         case DO_EXTENSION:
15158                         case DO_TYPE:
15159                         case DO_SHELL_TYPE:
15160                         case DO_FUNC:
15161                         case DO_AGG:
15162                         case DO_OPERATOR:
15163                         case DO_OPCLASS:
15164                         case DO_OPFAMILY:
15165                         case DO_COLLATION:
15166                         case DO_CONVERSION:
15167                         case DO_TABLE:
15168                         case DO_ATTRDEF:
15169                         case DO_PROCLANG:
15170                         case DO_CAST:
15171                         case DO_DUMMY_TYPE:
15172                         case DO_TSPARSER:
15173                         case DO_TSDICT:
15174                         case DO_TSTEMPLATE:
15175                         case DO_TSCONFIG:
15176                         case DO_FDW:
15177                         case DO_FOREIGN_SERVER:
15178                         case DO_BLOB:
15179                                 /* Pre-data objects: must come before the pre-data boundary */
15180                                 addObjectDependency(preDataBound, dobj->dumpId);
15181                                 break;
15182                         case DO_TABLE_DATA:
15183                         case DO_BLOB_DATA:
15184                                 /* Data objects: must come between the boundaries */
15185                                 addObjectDependency(dobj, preDataBound->dumpId);
15186                                 addObjectDependency(postDataBound, dobj->dumpId);
15187                                 break;
15188                         case DO_INDEX:
15189                         case DO_REFRESH_MATVIEW:
15190                         case DO_TRIGGER:
15191                         case DO_EVENT_TRIGGER:
15192                         case DO_DEFAULT_ACL:
15193                                 /* Post-data objects: must come after the post-data boundary */
15194                                 addObjectDependency(dobj, postDataBound->dumpId);
15195                                 break;
15196                         case DO_RULE:
15197                                 /* Rules are post-data, but only if dumped separately */
15198                                 if (((RuleInfo *) dobj)->separate)
15199                                         addObjectDependency(dobj, postDataBound->dumpId);
15200                                 break;
15201                         case DO_CONSTRAINT:
15202                         case DO_FK_CONSTRAINT:
15203                                 /* Constraints are post-data, but only if dumped separately */
15204                                 if (((ConstraintInfo *) dobj)->separate)
15205                                         addObjectDependency(dobj, postDataBound->dumpId);
15206                                 break;
15207                         case DO_PRE_DATA_BOUNDARY:
15208                                 /* nothing to do */
15209                                 break;
15210                         case DO_POST_DATA_BOUNDARY:
15211                                 /* must come after the pre-data boundary */
15212                                 addObjectDependency(dobj, preDataBound->dumpId);
15213                                 break;
15214                 }
15215         }
15216 }
15217
15218
15219 /*
15220  * BuildArchiveDependencies - create dependency data for archive TOC entries
15221  *
15222  * The raw dependency data obtained by getDependencies() is not terribly
15223  * useful in an archive dump, because in many cases there are dependency
15224  * chains linking through objects that don't appear explicitly in the dump.
15225  * For example, a view will depend on its _RETURN rule while the _RETURN rule
15226  * will depend on other objects --- but the rule will not appear as a separate
15227  * object in the dump.  We need to adjust the view's dependencies to include
15228  * whatever the rule depends on that is included in the dump.
15229  *
15230  * Just to make things more complicated, there are also "special" dependencies
15231  * such as the dependency of a TABLE DATA item on its TABLE, which we must
15232  * not rearrange because pg_restore knows that TABLE DATA only depends on
15233  * its table.  In these cases we must leave the dependencies strictly as-is
15234  * even if they refer to not-to-be-dumped objects.
15235  *
15236  * To handle this, the convention is that "special" dependencies are created
15237  * during ArchiveEntry calls, and an archive TOC item that has any such
15238  * entries will not be touched here.  Otherwise, we recursively search the
15239  * DumpableObject data structures to build the correct dependencies for each
15240  * archive TOC item.
15241  */
15242 static void
15243 BuildArchiveDependencies(Archive *fout)
15244 {
15245         ArchiveHandle *AH = (ArchiveHandle *) fout;
15246         TocEntry   *te;
15247
15248         /* Scan all TOC entries in the archive */
15249         for (te = AH->toc->next; te != AH->toc; te = te->next)
15250         {
15251                 DumpableObject *dobj;
15252                 DumpId     *dependencies;
15253                 int                     nDeps;
15254                 int                     allocDeps;
15255
15256                 /* No need to process entries that will not be dumped */
15257                 if (te->reqs == 0)
15258                         continue;
15259                 /* Ignore entries that already have "special" dependencies */
15260                 if (te->nDeps > 0)
15261                         continue;
15262                 /* Otherwise, look up the item's original DumpableObject, if any */
15263                 dobj = findObjectByDumpId(te->dumpId);
15264                 if (dobj == NULL)
15265                         continue;
15266                 /* No work if it has no dependencies */
15267                 if (dobj->nDeps <= 0)
15268                         continue;
15269                 /* Set up work array */
15270                 allocDeps = 64;
15271                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
15272                 nDeps = 0;
15273                 /* Recursively find all dumpable dependencies */
15274                 findDumpableDependencies(AH, dobj,
15275                                                                  &dependencies, &nDeps, &allocDeps);
15276                 /* And save 'em ... */
15277                 if (nDeps > 0)
15278                 {
15279                         dependencies = (DumpId *) pg_realloc(dependencies,
15280                                                                                                  nDeps * sizeof(DumpId));
15281                         te->dependencies = dependencies;
15282                         te->nDeps = nDeps;
15283                 }
15284                 else
15285                         free(dependencies);
15286         }
15287 }
15288
15289 /* Recursive search subroutine for BuildArchiveDependencies */
15290 static void
15291 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
15292                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
15293 {
15294         int                     i;
15295
15296         /*
15297          * Ignore section boundary objects: if we search through them, we'll
15298          * report lots of bogus dependencies.
15299          */
15300         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15301                 dobj->objType == DO_POST_DATA_BOUNDARY)
15302                 return;
15303
15304         for (i = 0; i < dobj->nDeps; i++)
15305         {
15306                 DumpId          depid = dobj->dependencies[i];
15307
15308                 if (TocIDRequired(AH, depid) != 0)
15309                 {
15310                         /* Object will be dumped, so just reference it as a dependency */
15311                         if (*nDeps >= *allocDeps)
15312                         {
15313                                 *allocDeps *= 2;
15314                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15315                                                                                                 *allocDeps * sizeof(DumpId));
15316                         }
15317                         (*dependencies)[*nDeps] = depid;
15318                         (*nDeps)++;
15319                 }
15320                 else
15321                 {
15322                         /*
15323                          * Object will not be dumped, so recursively consider its deps. We
15324                          * rely on the assumption that sortDumpableObjects already broke
15325                          * any dependency loops, else we might recurse infinitely.
15326                          */
15327                         DumpableObject *otherdobj = findObjectByDumpId(depid);
15328
15329                         if (otherdobj)
15330                                 findDumpableDependencies(AH, otherdobj,
15331                                                                                  dependencies, nDeps, allocDeps);
15332                 }
15333         }
15334 }
15335
15336
15337 /*
15338  * selectSourceSchema - make the specified schema the active search path
15339  * in the source database.
15340  *
15341  * NB: pg_catalog is explicitly searched after the specified schema;
15342  * so user names are only qualified if they are cross-schema references,
15343  * and system names are only qualified if they conflict with a user name
15344  * in the current schema.
15345  *
15346  * Whenever the selected schema is not pg_catalog, be careful to qualify
15347  * references to system catalogs and types in our emitted commands!
15348  *
15349  * This function is called only from selectSourceSchemaOnAH and
15350  * selectSourceSchema.
15351  */
15352 static void
15353 selectSourceSchema(Archive *fout, const char *schemaName)
15354 {
15355         PQExpBuffer query;
15356
15357         /* This is checked by the callers already */
15358         Assert(schemaName != NULL && *schemaName != '\0');
15359
15360         /* Not relevant if fetching from pre-7.3 DB */
15361         if (fout->remoteVersion < 70300)
15362                 return;
15363
15364         query = createPQExpBuffer();
15365         appendPQExpBuffer(query, "SET search_path = %s",
15366                                           fmtId(schemaName));
15367         if (strcmp(schemaName, "pg_catalog") != 0)
15368                 appendPQExpBufferStr(query, ", pg_catalog");
15369
15370         ExecuteSqlStatement(fout, query->data);
15371
15372         destroyPQExpBuffer(query);
15373 }
15374
15375 /*
15376  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15377  * given type name.
15378  *
15379  * NB: in 7.3 and up the result may depend on the currently-selected
15380  * schema; this is why we don't try to cache the names.
15381  */
15382 static char *
15383 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15384 {
15385         char       *result;
15386         PQExpBuffer query;
15387         PGresult   *res;
15388
15389         if (oid == 0)
15390         {
15391                 if ((opts & zeroAsOpaque) != 0)
15392                         return pg_strdup(g_opaque_type);
15393                 else if ((opts & zeroAsAny) != 0)
15394                         return pg_strdup("'any'");
15395                 else if ((opts & zeroAsStar) != 0)
15396                         return pg_strdup("*");
15397                 else if ((opts & zeroAsNone) != 0)
15398                         return pg_strdup("NONE");
15399         }
15400
15401         query = createPQExpBuffer();
15402         if (fout->remoteVersion >= 70300)
15403         {
15404                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15405                                                   oid);
15406         }
15407         else if (fout->remoteVersion >= 70100)
15408         {
15409                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15410                                                   oid);
15411         }
15412         else
15413         {
15414                 appendPQExpBuffer(query, "SELECT typname "
15415                                                   "FROM pg_type "
15416                                                   "WHERE oid = '%u'::oid",
15417                                                   oid);
15418         }
15419
15420         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15421
15422         if (fout->remoteVersion >= 70100)
15423         {
15424                 /* already quoted */
15425                 result = pg_strdup(PQgetvalue(res, 0, 0));
15426         }
15427         else
15428         {
15429                 /* may need to quote it */
15430                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15431         }
15432
15433         PQclear(res);
15434         destroyPQExpBuffer(query);
15435
15436         return result;
15437 }
15438
15439 /*
15440  * myFormatType --- local implementation of format_type for use with 7.0.
15441  */
15442 static char *
15443 myFormatType(const char *typname, int32 typmod)
15444 {
15445         char       *result;
15446         bool            isarray = false;
15447         PQExpBuffer buf = createPQExpBuffer();
15448
15449         /* Handle array types */
15450         if (typname[0] == '_')
15451         {
15452                 isarray = true;
15453                 typname++;
15454         }
15455
15456         /* Show lengths on bpchar and varchar */
15457         if (strcmp(typname, "bpchar") == 0)
15458         {
15459                 int                     len = (typmod - VARHDRSZ);
15460
15461                 appendPQExpBufferStr(buf, "character");
15462                 if (len > 1)
15463                         appendPQExpBuffer(buf, "(%d)",
15464                                                           typmod - VARHDRSZ);
15465         }
15466         else if (strcmp(typname, "varchar") == 0)
15467         {
15468                 appendPQExpBufferStr(buf, "character varying");
15469                 if (typmod != -1)
15470                         appendPQExpBuffer(buf, "(%d)",
15471                                                           typmod - VARHDRSZ);
15472         }
15473         else if (strcmp(typname, "numeric") == 0)
15474         {
15475                 appendPQExpBufferStr(buf, "numeric");
15476                 if (typmod != -1)
15477                 {
15478                         int32           tmp_typmod;
15479                         int                     precision;
15480                         int                     scale;
15481
15482                         tmp_typmod = typmod - VARHDRSZ;
15483                         precision = (tmp_typmod >> 16) & 0xffff;
15484                         scale = tmp_typmod & 0xffff;
15485                         appendPQExpBuffer(buf, "(%d,%d)",
15486                                                           precision, scale);
15487                 }
15488         }
15489
15490         /*
15491          * char is an internal single-byte data type; Let's make sure we force it
15492          * through with quotes. - thomas 1998-12-13
15493          */
15494         else if (strcmp(typname, "char") == 0)
15495                 appendPQExpBufferStr(buf, "\"char\"");
15496         else
15497                 appendPQExpBufferStr(buf, fmtId(typname));
15498
15499         /* Append array qualifier for array types */
15500         if (isarray)
15501                 appendPQExpBufferStr(buf, "[]");
15502
15503         result = pg_strdup(buf->data);
15504         destroyPQExpBuffer(buf);
15505
15506         return result;
15507 }
15508
15509 /*
15510  * Return a column list clause for the given relation.
15511  *
15512  * Special case: if there are no undropped columns in the relation, return
15513  * "", not an invalid "()" column list.
15514  */
15515 static const char *
15516 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15517 {
15518         int                     numatts = ti->numatts;
15519         char      **attnames = ti->attnames;
15520         bool       *attisdropped = ti->attisdropped;
15521         bool            needComma;
15522         int                     i;
15523
15524         appendPQExpBufferChar(buffer, '(');
15525         needComma = false;
15526         for (i = 0; i < numatts; i++)
15527         {
15528                 if (attisdropped[i])
15529                         continue;
15530                 if (needComma)
15531                         appendPQExpBufferStr(buffer, ", ");
15532                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
15533                 needComma = true;
15534         }
15535
15536         if (!needComma)
15537                 return "";                              /* no undropped columns */
15538
15539         appendPQExpBufferChar(buffer, ')');
15540         return buffer->data;
15541 }
15542
15543 /*
15544  * Execute an SQL query and verify that we got exactly one row back.
15545  */
15546 static PGresult *
15547 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15548 {
15549         PGresult   *res;
15550         int                     ntups;
15551
15552         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15553
15554         /* Expecting a single result only */
15555         ntups = PQntuples(res);
15556         if (ntups != 1)
15557                 exit_horribly(NULL,
15558                                           ngettext("query returned %d row instead of one: %s\n",
15559                                                            "query returned %d rows instead of one: %s\n",
15560                                                            ntups),
15561                                           ntups, query);
15562
15563         return res;
15564 }