]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
799637d62e1d718ab92d2347e4f678dd58fe8ad6
[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 ExecuteSimpleCommands(), 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                 tblinfo[i].postponed_def = false;               /* might get set during sort */
4800
4801                 /*
4802                  * Read-lock target tables to make sure they aren't DROPPED or altered
4803                  * in schema before we get around to dumping them.
4804                  *
4805                  * Note that we don't explicitly lock parents of the target tables; we
4806                  * assume our lock on the child is enough to prevent schema
4807                  * alterations to parent tables.
4808                  *
4809                  * NOTE: it'd be kinda nice to lock other relations too, not only
4810                  * plain tables, but the backend doesn't presently allow that.
4811                  */
4812                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4813                 {
4814                         resetPQExpBuffer(query);
4815                         appendPQExpBuffer(query,
4816                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4817                                                           fmtQualifiedId(fout->remoteVersion,
4818                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4819                                                                                          tblinfo[i].dobj.name));
4820                         ExecuteSqlStatement(fout, query->data);
4821                 }
4822
4823                 /* Emit notice if join for owner failed */
4824                 if (strlen(tblinfo[i].rolname) == 0)
4825                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4826                                           tblinfo[i].dobj.name);
4827         }
4828
4829         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4830         {
4831                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4832         }
4833
4834         PQclear(res);
4835
4836         destroyPQExpBuffer(query);
4837
4838         return tblinfo;
4839 }
4840
4841 /*
4842  * getOwnedSeqs
4843  *        identify owned sequences and mark them as dumpable if owning table is
4844  *
4845  * We used to do this in getTables(), but it's better to do it after the
4846  * index used by findTableByOid() has been set up.
4847  */
4848 void
4849 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4850 {
4851         int                     i;
4852
4853         /*
4854          * Force sequences that are "owned" by table columns to be dumped whenever
4855          * their owning table is being dumped.
4856          */
4857         for (i = 0; i < numTables; i++)
4858         {
4859                 TableInfo  *seqinfo = &tblinfo[i];
4860                 TableInfo  *owning_tab;
4861
4862                 if (!OidIsValid(seqinfo->owning_tab))
4863                         continue;                       /* not an owned sequence */
4864                 if (seqinfo->dobj.dump)
4865                         continue;                       /* no need to search */
4866                 owning_tab = findTableByOid(seqinfo->owning_tab);
4867                 if (owning_tab && owning_tab->dobj.dump)
4868                 {
4869                         seqinfo->interesting = true;
4870                         seqinfo->dobj.dump = true;
4871                 }
4872         }
4873 }
4874
4875 /*
4876  * getInherits
4877  *        read all the inheritance information
4878  * from the system catalogs return them in the InhInfo* structure
4879  *
4880  * numInherits is set to the number of pairs read in
4881  */
4882 InhInfo *
4883 getInherits(Archive *fout, int *numInherits)
4884 {
4885         PGresult   *res;
4886         int                     ntups;
4887         int                     i;
4888         PQExpBuffer query = createPQExpBuffer();
4889         InhInfo    *inhinfo;
4890
4891         int                     i_inhrelid;
4892         int                     i_inhparent;
4893
4894         /* Make sure we are in proper schema */
4895         selectSourceSchema(fout, "pg_catalog");
4896
4897         /* find all the inheritance information */
4898
4899         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4900
4901         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4902
4903         ntups = PQntuples(res);
4904
4905         *numInherits = ntups;
4906
4907         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4908
4909         i_inhrelid = PQfnumber(res, "inhrelid");
4910         i_inhparent = PQfnumber(res, "inhparent");
4911
4912         for (i = 0; i < ntups; i++)
4913         {
4914                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4915                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4916         }
4917
4918         PQclear(res);
4919
4920         destroyPQExpBuffer(query);
4921
4922         return inhinfo;
4923 }
4924
4925 /*
4926  * getIndexes
4927  *        get information about every index on a dumpable table
4928  *
4929  * Note: index data is not returned directly to the caller, but it
4930  * does get entered into the DumpableObject tables.
4931  */
4932 void
4933 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4934 {
4935         int                     i,
4936                                 j;
4937         PQExpBuffer query = createPQExpBuffer();
4938         PGresult   *res;
4939         IndxInfo   *indxinfo;
4940         ConstraintInfo *constrinfo;
4941         int                     i_tableoid,
4942                                 i_oid,
4943                                 i_indexname,
4944                                 i_indexdef,
4945                                 i_indnkeys,
4946                                 i_indkey,
4947                                 i_indisclustered,
4948                                 i_indisreplident,
4949                                 i_contype,
4950                                 i_conname,
4951                                 i_condeferrable,
4952                                 i_condeferred,
4953                                 i_contableoid,
4954                                 i_conoid,
4955                                 i_condef,
4956                                 i_tablespace,
4957                                 i_options,
4958                                 i_relpages;
4959         int                     ntups;
4960
4961         for (i = 0; i < numTables; i++)
4962         {
4963                 TableInfo  *tbinfo = &tblinfo[i];
4964
4965                 /* Only plain tables and materialized views have indexes. */
4966                 if (tbinfo->relkind != RELKIND_RELATION &&
4967                         tbinfo->relkind != RELKIND_MATVIEW)
4968                         continue;
4969                 if (!tbinfo->hasindex)
4970                         continue;
4971
4972                 /* Ignore indexes of tables not to be dumped */
4973                 if (!tbinfo->dobj.dump)
4974                         continue;
4975
4976                 if (g_verbose)
4977                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4978                                           tbinfo->dobj.name);
4979
4980                 /* Make sure we are in proper schema so indexdef is right */
4981                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4982
4983                 /*
4984                  * The point of the messy-looking outer join is to find a constraint
4985                  * that is related by an internal dependency link to the index. If we
4986                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4987                  * assume an index won't have more than one internal dependency.
4988                  *
4989                  * As of 9.0 we don't need to look at pg_depend but can check for a
4990                  * match to pg_constraint.conindid.  The check on conrelid is
4991                  * redundant but useful because that column is indexed while conindid
4992                  * is not.
4993                  */
4994                 resetPQExpBuffer(query);
4995                 if (fout->remoteVersion >= 90400)
4996                 {
4997                         /*
4998                          * the test on indisready is necessary in 9.2, and harmless in
4999                          * earlier/later versions
5000                          */
5001                         appendPQExpBuffer(query,
5002                                                           "SELECT t.tableoid, t.oid, "
5003                                                           "t.relname AS indexname, "
5004                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5005                                                           "t.relnatts AS indnkeys, "
5006                                                           "i.indkey, i.indisclustered, "
5007                                                           "i.indisreplident, t.relpages, "
5008                                                           "c.contype, c.conname, "
5009                                                           "c.condeferrable, c.condeferred, "
5010                                                           "c.tableoid AS contableoid, "
5011                                                           "c.oid AS conoid, "
5012                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5013                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5014                                                         "array_to_string(t.reloptions, ', ') AS options "
5015                                                           "FROM pg_catalog.pg_index i "
5016                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5017                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5018                                                           "ON (i.indrelid = c.conrelid AND "
5019                                                           "i.indexrelid = c.conindid AND "
5020                                                           "c.contype IN ('p','u','x')) "
5021                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5022                                                           "AND i.indisvalid AND i.indisready "
5023                                                           "ORDER BY indexname",
5024                                                           tbinfo->dobj.catId.oid);
5025                 }
5026                 else if (fout->remoteVersion >= 90000)
5027                 {
5028                         /*
5029                          * the test on indisready is necessary in 9.2, and harmless in
5030                          * earlier/later versions
5031                          */
5032                         appendPQExpBuffer(query,
5033                                                           "SELECT t.tableoid, t.oid, "
5034                                                           "t.relname AS indexname, "
5035                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5036                                                           "t.relnatts AS indnkeys, "
5037                                                           "i.indkey, i.indisclustered, "
5038                                                           "false AS indisreplident, t.relpages, "
5039                                                           "c.contype, c.conname, "
5040                                                           "c.condeferrable, c.condeferred, "
5041                                                           "c.tableoid AS contableoid, "
5042                                                           "c.oid AS conoid, "
5043                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5044                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5045                                                         "array_to_string(t.reloptions, ', ') AS options "
5046                                                           "FROM pg_catalog.pg_index i "
5047                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5048                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5049                                                           "ON (i.indrelid = c.conrelid AND "
5050                                                           "i.indexrelid = c.conindid AND "
5051                                                           "c.contype IN ('p','u','x')) "
5052                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5053                                                           "AND i.indisvalid AND i.indisready "
5054                                                           "ORDER BY indexname",
5055                                                           tbinfo->dobj.catId.oid);
5056                 }
5057                 else if (fout->remoteVersion >= 80200)
5058                 {
5059                         appendPQExpBuffer(query,
5060                                                           "SELECT t.tableoid, t.oid, "
5061                                                           "t.relname AS indexname, "
5062                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5063                                                           "t.relnatts AS indnkeys, "
5064                                                           "i.indkey, i.indisclustered, "
5065                                                           "false AS indisreplident, t.relpages, "
5066                                                           "c.contype, c.conname, "
5067                                                           "c.condeferrable, c.condeferred, "
5068                                                           "c.tableoid AS contableoid, "
5069                                                           "c.oid AS conoid, "
5070                                                           "null AS condef, "
5071                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5072                                                         "array_to_string(t.reloptions, ', ') AS options "
5073                                                           "FROM pg_catalog.pg_index i "
5074                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5075                                                           "LEFT JOIN pg_catalog.pg_depend d "
5076                                                           "ON (d.classid = t.tableoid "
5077                                                           "AND d.objid = t.oid "
5078                                                           "AND d.deptype = 'i') "
5079                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5080                                                           "ON (d.refclassid = c.tableoid "
5081                                                           "AND d.refobjid = c.oid) "
5082                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5083                                                           "AND i.indisvalid "
5084                                                           "ORDER BY indexname",
5085                                                           tbinfo->dobj.catId.oid);
5086                 }
5087                 else if (fout->remoteVersion >= 80000)
5088                 {
5089                         appendPQExpBuffer(query,
5090                                                           "SELECT t.tableoid, t.oid, "
5091                                                           "t.relname AS indexname, "
5092                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5093                                                           "t.relnatts AS indnkeys, "
5094                                                           "i.indkey, i.indisclustered, "
5095                                                           "false AS indisreplident, t.relpages, "
5096                                                           "c.contype, c.conname, "
5097                                                           "c.condeferrable, c.condeferred, "
5098                                                           "c.tableoid AS contableoid, "
5099                                                           "c.oid AS conoid, "
5100                                                           "null AS condef, "
5101                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5102                                                           "null AS options "
5103                                                           "FROM pg_catalog.pg_index i "
5104                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5105                                                           "LEFT JOIN pg_catalog.pg_depend d "
5106                                                           "ON (d.classid = t.tableoid "
5107                                                           "AND d.objid = t.oid "
5108                                                           "AND d.deptype = 'i') "
5109                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5110                                                           "ON (d.refclassid = c.tableoid "
5111                                                           "AND d.refobjid = c.oid) "
5112                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5113                                                           "ORDER BY indexname",
5114                                                           tbinfo->dobj.catId.oid);
5115                 }
5116                 else if (fout->remoteVersion >= 70300)
5117                 {
5118                         appendPQExpBuffer(query,
5119                                                           "SELECT t.tableoid, t.oid, "
5120                                                           "t.relname AS indexname, "
5121                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5122                                                           "t.relnatts AS indnkeys, "
5123                                                           "i.indkey, i.indisclustered, "
5124                                                           "false AS indisreplident, t.relpages, "
5125                                                           "c.contype, c.conname, "
5126                                                           "c.condeferrable, c.condeferred, "
5127                                                           "c.tableoid AS contableoid, "
5128                                                           "c.oid AS conoid, "
5129                                                           "null AS condef, "
5130                                                           "NULL AS tablespace, "
5131                                                           "null AS options "
5132                                                           "FROM pg_catalog.pg_index i "
5133                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5134                                                           "LEFT JOIN pg_catalog.pg_depend d "
5135                                                           "ON (d.classid = t.tableoid "
5136                                                           "AND d.objid = t.oid "
5137                                                           "AND d.deptype = 'i') "
5138                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5139                                                           "ON (d.refclassid = c.tableoid "
5140                                                           "AND d.refobjid = c.oid) "
5141                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5142                                                           "ORDER BY indexname",
5143                                                           tbinfo->dobj.catId.oid);
5144                 }
5145                 else if (fout->remoteVersion >= 70100)
5146                 {
5147                         appendPQExpBuffer(query,
5148                                                           "SELECT t.tableoid, t.oid, "
5149                                                           "t.relname AS indexname, "
5150                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5151                                                           "t.relnatts AS indnkeys, "
5152                                                           "i.indkey, false AS indisclustered, "
5153                                                           "false AS indisreplident, t.relpages, "
5154                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5155                                                           "ELSE '0'::char END AS contype, "
5156                                                           "t.relname AS conname, "
5157                                                           "false AS condeferrable, "
5158                                                           "false AS condeferred, "
5159                                                           "0::oid AS contableoid, "
5160                                                           "t.oid AS conoid, "
5161                                                           "null AS condef, "
5162                                                           "NULL AS tablespace, "
5163                                                           "null AS options "
5164                                                           "FROM pg_index i, pg_class t "
5165                                                           "WHERE t.oid = i.indexrelid "
5166                                                           "AND i.indrelid = '%u'::oid "
5167                                                           "ORDER BY indexname",
5168                                                           tbinfo->dobj.catId.oid);
5169                 }
5170                 else
5171                 {
5172                         appendPQExpBuffer(query,
5173                                                           "SELECT "
5174                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5175                                                           "t.oid, "
5176                                                           "t.relname AS indexname, "
5177                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5178                                                           "t.relnatts AS indnkeys, "
5179                                                           "i.indkey, false AS indisclustered, "
5180                                                           "false AS indisreplident, t.relpages, "
5181                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5182                                                           "ELSE '0'::char END AS contype, "
5183                                                           "t.relname AS conname, "
5184                                                           "false AS condeferrable, "
5185                                                           "false AS condeferred, "
5186                                                           "0::oid AS contableoid, "
5187                                                           "t.oid AS conoid, "
5188                                                           "null AS condef, "
5189                                                           "NULL AS tablespace, "
5190                                                           "null AS options "
5191                                                           "FROM pg_index i, pg_class t "
5192                                                           "WHERE t.oid = i.indexrelid "
5193                                                           "AND i.indrelid = '%u'::oid "
5194                                                           "ORDER BY indexname",
5195                                                           tbinfo->dobj.catId.oid);
5196                 }
5197
5198                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5199
5200                 ntups = PQntuples(res);
5201
5202                 i_tableoid = PQfnumber(res, "tableoid");
5203                 i_oid = PQfnumber(res, "oid");
5204                 i_indexname = PQfnumber(res, "indexname");
5205                 i_indexdef = PQfnumber(res, "indexdef");
5206                 i_indnkeys = PQfnumber(res, "indnkeys");
5207                 i_indkey = PQfnumber(res, "indkey");
5208                 i_indisclustered = PQfnumber(res, "indisclustered");
5209                 i_indisreplident = PQfnumber(res, "indisreplident");
5210                 i_relpages = PQfnumber(res, "relpages");
5211                 i_contype = PQfnumber(res, "contype");
5212                 i_conname = PQfnumber(res, "conname");
5213                 i_condeferrable = PQfnumber(res, "condeferrable");
5214                 i_condeferred = PQfnumber(res, "condeferred");
5215                 i_contableoid = PQfnumber(res, "contableoid");
5216                 i_conoid = PQfnumber(res, "conoid");
5217                 i_condef = PQfnumber(res, "condef");
5218                 i_tablespace = PQfnumber(res, "tablespace");
5219                 i_options = PQfnumber(res, "options");
5220
5221                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5222                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5223
5224                 for (j = 0; j < ntups; j++)
5225                 {
5226                         char            contype;
5227
5228                         indxinfo[j].dobj.objType = DO_INDEX;
5229                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5230                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5231                         AssignDumpId(&indxinfo[j].dobj);
5232                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5233                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5234                         indxinfo[j].indextable = tbinfo;
5235                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5236                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5237                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5238                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5239
5240                         /*
5241                          * In pre-7.4 releases, indkeys may contain more entries than
5242                          * indnkeys says (since indnkeys will be 1 for a functional
5243                          * index).  We don't actually care about this case since we don't
5244                          * examine indkeys except for indexes associated with PRIMARY and
5245                          * UNIQUE constraints, which are never functional indexes. But we
5246                          * have to allocate enough space to keep parseOidArray from
5247                          * complaining.
5248                          */
5249                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5250                         parseOidArray(PQgetvalue(res, j, i_indkey),
5251                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5252                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5253                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
5254                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5255                         contype = *(PQgetvalue(res, j, i_contype));
5256
5257                         if (contype == 'p' || contype == 'u' || contype == 'x')
5258                         {
5259                                 /*
5260                                  * If we found a constraint matching the index, create an
5261                                  * entry for it.
5262                                  *
5263                                  * In a pre-7.3 database, we take this path iff the index was
5264                                  * marked indisprimary.
5265                                  */
5266                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5267                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5268                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5269                                 AssignDumpId(&constrinfo[j].dobj);
5270                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5271                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5272                                 constrinfo[j].contable = tbinfo;
5273                                 constrinfo[j].condomain = NULL;
5274                                 constrinfo[j].contype = contype;
5275                                 if (contype == 'x')
5276                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5277                                 else
5278                                         constrinfo[j].condef = NULL;
5279                                 constrinfo[j].confrelid = InvalidOid;
5280                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5281                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5282                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5283                                 constrinfo[j].conislocal = true;
5284                                 constrinfo[j].separate = true;
5285
5286                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5287
5288                                 /* If pre-7.3 DB, better make sure table comes first */
5289                                 addObjectDependency(&constrinfo[j].dobj,
5290                                                                         tbinfo->dobj.dumpId);
5291                         }
5292                         else
5293                         {
5294                                 /* Plain secondary index */
5295                                 indxinfo[j].indexconstraint = 0;
5296                         }
5297                 }
5298
5299                 PQclear(res);
5300         }
5301
5302         destroyPQExpBuffer(query);
5303 }
5304
5305 /*
5306  * getConstraints
5307  *
5308  * Get info about constraints on dumpable tables.
5309  *
5310  * Currently handles foreign keys only.
5311  * Unique and primary key constraints are handled with indexes,
5312  * while check constraints are processed in getTableAttrs().
5313  */
5314 void
5315 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5316 {
5317         int                     i,
5318                                 j;
5319         ConstraintInfo *constrinfo;
5320         PQExpBuffer query;
5321         PGresult   *res;
5322         int                     i_contableoid,
5323                                 i_conoid,
5324                                 i_conname,
5325                                 i_confrelid,
5326                                 i_condef;
5327         int                     ntups;
5328
5329         /* pg_constraint was created in 7.3, so nothing to do if older */
5330         if (fout->remoteVersion < 70300)
5331                 return;
5332
5333         query = createPQExpBuffer();
5334
5335         for (i = 0; i < numTables; i++)
5336         {
5337                 TableInfo  *tbinfo = &tblinfo[i];
5338
5339                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5340                         continue;
5341
5342                 if (g_verbose)
5343                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
5344                                           tbinfo->dobj.name);
5345
5346                 /*
5347                  * select table schema to ensure constraint expr is qualified if
5348                  * needed
5349                  */
5350                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5351
5352                 resetPQExpBuffer(query);
5353                 appendPQExpBuffer(query,
5354                                                   "SELECT tableoid, oid, conname, confrelid, "
5355                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5356                                                   "FROM pg_catalog.pg_constraint "
5357                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5358                                                   "AND contype = 'f'",
5359                                                   tbinfo->dobj.catId.oid);
5360                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5361
5362                 ntups = PQntuples(res);
5363
5364                 i_contableoid = PQfnumber(res, "tableoid");
5365                 i_conoid = PQfnumber(res, "oid");
5366                 i_conname = PQfnumber(res, "conname");
5367                 i_confrelid = PQfnumber(res, "confrelid");
5368                 i_condef = PQfnumber(res, "condef");
5369
5370                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5371
5372                 for (j = 0; j < ntups; j++)
5373                 {
5374                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5375                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5376                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5377                         AssignDumpId(&constrinfo[j].dobj);
5378                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5379                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5380                         constrinfo[j].contable = tbinfo;
5381                         constrinfo[j].condomain = NULL;
5382                         constrinfo[j].contype = 'f';
5383                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5384                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5385                         constrinfo[j].conindex = 0;
5386                         constrinfo[j].condeferrable = false;
5387                         constrinfo[j].condeferred = false;
5388                         constrinfo[j].conislocal = true;
5389                         constrinfo[j].separate = true;
5390                 }
5391
5392                 PQclear(res);
5393         }
5394
5395         destroyPQExpBuffer(query);
5396 }
5397
5398 /*
5399  * getDomainConstraints
5400  *
5401  * Get info about constraints on a domain.
5402  */
5403 static void
5404 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5405 {
5406         int                     i;
5407         ConstraintInfo *constrinfo;
5408         PQExpBuffer query;
5409         PGresult   *res;
5410         int                     i_tableoid,
5411                                 i_oid,
5412                                 i_conname,
5413                                 i_consrc;
5414         int                     ntups;
5415
5416         /* pg_constraint was created in 7.3, so nothing to do if older */
5417         if (fout->remoteVersion < 70300)
5418                 return;
5419
5420         /*
5421          * select appropriate schema to ensure names in constraint are properly
5422          * qualified
5423          */
5424         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5425
5426         query = createPQExpBuffer();
5427
5428         if (fout->remoteVersion >= 90100)
5429                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5430                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5431                                                   "convalidated "
5432                                                   "FROM pg_catalog.pg_constraint "
5433                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5434                                                   "ORDER BY conname",
5435                                                   tyinfo->dobj.catId.oid);
5436
5437         else if (fout->remoteVersion >= 70400)
5438                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5439                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5440                                                   "true as convalidated "
5441                                                   "FROM pg_catalog.pg_constraint "
5442                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5443                                                   "ORDER BY conname",
5444                                                   tyinfo->dobj.catId.oid);
5445         else
5446                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5447                                                   "'CHECK (' || consrc || ')' AS consrc, "
5448                                                   "true as convalidated "
5449                                                   "FROM pg_catalog.pg_constraint "
5450                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5451                                                   "ORDER BY conname",
5452                                                   tyinfo->dobj.catId.oid);
5453
5454         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5455
5456         ntups = PQntuples(res);
5457
5458         i_tableoid = PQfnumber(res, "tableoid");
5459         i_oid = PQfnumber(res, "oid");
5460         i_conname = PQfnumber(res, "conname");
5461         i_consrc = PQfnumber(res, "consrc");
5462
5463         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5464
5465         tyinfo->nDomChecks = ntups;
5466         tyinfo->domChecks = constrinfo;
5467
5468         for (i = 0; i < ntups; i++)
5469         {
5470                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5471
5472                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5473                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5474                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5475                 AssignDumpId(&constrinfo[i].dobj);
5476                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5477                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5478                 constrinfo[i].contable = NULL;
5479                 constrinfo[i].condomain = tyinfo;
5480                 constrinfo[i].contype = 'c';
5481                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5482                 constrinfo[i].confrelid = InvalidOid;
5483                 constrinfo[i].conindex = 0;
5484                 constrinfo[i].condeferrable = false;
5485                 constrinfo[i].condeferred = false;
5486                 constrinfo[i].conislocal = true;
5487
5488                 constrinfo[i].separate = !validated;
5489
5490                 /*
5491                  * Make the domain depend on the constraint, ensuring it won't be
5492                  * output till any constraint dependencies are OK.  If the constraint
5493                  * has not been validated, it's going to be dumped after the domain
5494                  * anyway, so this doesn't matter.
5495                  */
5496                 if (validated)
5497                         addObjectDependency(&tyinfo->dobj,
5498                                                                 constrinfo[i].dobj.dumpId);
5499         }
5500
5501         PQclear(res);
5502
5503         destroyPQExpBuffer(query);
5504 }
5505
5506 /*
5507  * getRules
5508  *        get basic information about every rule in the system
5509  *
5510  * numRules is set to the number of rules read in
5511  */
5512 RuleInfo *
5513 getRules(Archive *fout, int *numRules)
5514 {
5515         PGresult   *res;
5516         int                     ntups;
5517         int                     i;
5518         PQExpBuffer query = createPQExpBuffer();
5519         RuleInfo   *ruleinfo;
5520         int                     i_tableoid;
5521         int                     i_oid;
5522         int                     i_rulename;
5523         int                     i_ruletable;
5524         int                     i_ev_type;
5525         int                     i_is_instead;
5526         int                     i_ev_enabled;
5527
5528         /* Make sure we are in proper schema */
5529         selectSourceSchema(fout, "pg_catalog");
5530
5531         if (fout->remoteVersion >= 80300)
5532         {
5533                 appendPQExpBufferStr(query, "SELECT "
5534                                                          "tableoid, oid, rulename, "
5535                                                          "ev_class AS ruletable, ev_type, is_instead, "
5536                                                          "ev_enabled "
5537                                                          "FROM pg_rewrite "
5538                                                          "ORDER BY oid");
5539         }
5540         else if (fout->remoteVersion >= 70100)
5541         {
5542                 appendPQExpBufferStr(query, "SELECT "
5543                                                          "tableoid, oid, rulename, "
5544                                                          "ev_class AS ruletable, ev_type, is_instead, "
5545                                                          "'O'::char AS ev_enabled "
5546                                                          "FROM pg_rewrite "
5547                                                          "ORDER BY oid");
5548         }
5549         else
5550         {
5551                 appendPQExpBufferStr(query, "SELECT "
5552                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5553                                                          "oid, rulename, "
5554                                                          "ev_class AS ruletable, ev_type, is_instead, "
5555                                                          "'O'::char AS ev_enabled "
5556                                                          "FROM pg_rewrite "
5557                                                          "ORDER BY oid");
5558         }
5559
5560         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5561
5562         ntups = PQntuples(res);
5563
5564         *numRules = ntups;
5565
5566         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5567
5568         i_tableoid = PQfnumber(res, "tableoid");
5569         i_oid = PQfnumber(res, "oid");
5570         i_rulename = PQfnumber(res, "rulename");
5571         i_ruletable = PQfnumber(res, "ruletable");
5572         i_ev_type = PQfnumber(res, "ev_type");
5573         i_is_instead = PQfnumber(res, "is_instead");
5574         i_ev_enabled = PQfnumber(res, "ev_enabled");
5575
5576         for (i = 0; i < ntups; i++)
5577         {
5578                 Oid                     ruletableoid;
5579
5580                 ruleinfo[i].dobj.objType = DO_RULE;
5581                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5582                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5583                 AssignDumpId(&ruleinfo[i].dobj);
5584                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5585                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5586                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5587                 if (ruleinfo[i].ruletable == NULL)
5588                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5589                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5590                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5591                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5592                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5593                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5594                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5595                 if (ruleinfo[i].ruletable)
5596                 {
5597                         /*
5598                          * If the table is a view or materialized view, force its ON
5599                          * SELECT rule to be sorted before the view itself --- this
5600                          * ensures that any dependencies for the rule affect the table's
5601                          * positioning. Other rules are forced to appear after their
5602                          * table.
5603                          */
5604                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5605                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5606                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5607                         {
5608                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5609                                                                         ruleinfo[i].dobj.dumpId);
5610                                 /* We'll merge the rule into CREATE VIEW, if possible */
5611                                 ruleinfo[i].separate = false;
5612                         }
5613                         else
5614                         {
5615                                 addObjectDependency(&ruleinfo[i].dobj,
5616                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5617                                 ruleinfo[i].separate = true;
5618                         }
5619                 }
5620                 else
5621                         ruleinfo[i].separate = true;
5622
5623                 /*
5624                  * If we're forced to break a dependency loop by dumping a view as a
5625                  * table and separate _RETURN rule, we'll move the view's reloptions
5626                  * to the rule.  (This is necessary because tables and views have
5627                  * different valid reloptions, so we can't apply the options until the
5628                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5629                  * NULL.
5630                  */
5631                 ruleinfo[i].reloptions = NULL;
5632         }
5633
5634         PQclear(res);
5635
5636         destroyPQExpBuffer(query);
5637
5638         return ruleinfo;
5639 }
5640
5641 /*
5642  * getTriggers
5643  *        get information about every trigger on a dumpable table
5644  *
5645  * Note: trigger data is not returned directly to the caller, but it
5646  * does get entered into the DumpableObject tables.
5647  */
5648 void
5649 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5650 {
5651         int                     i,
5652                                 j;
5653         PQExpBuffer query = createPQExpBuffer();
5654         PGresult   *res;
5655         TriggerInfo *tginfo;
5656         int                     i_tableoid,
5657                                 i_oid,
5658                                 i_tgname,
5659                                 i_tgfname,
5660                                 i_tgtype,
5661                                 i_tgnargs,
5662                                 i_tgargs,
5663                                 i_tgisconstraint,
5664                                 i_tgconstrname,
5665                                 i_tgconstrrelid,
5666                                 i_tgconstrrelname,
5667                                 i_tgenabled,
5668                                 i_tgdeferrable,
5669                                 i_tginitdeferred,
5670                                 i_tgdef;
5671         int                     ntups;
5672
5673         for (i = 0; i < numTables; i++)
5674         {
5675                 TableInfo  *tbinfo = &tblinfo[i];
5676
5677                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5678                         continue;
5679
5680                 if (g_verbose)
5681                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5682                                           tbinfo->dobj.name);
5683
5684                 /*
5685                  * select table schema to ensure regproc name is qualified if needed
5686                  */
5687                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5688
5689                 resetPQExpBuffer(query);
5690                 if (fout->remoteVersion >= 90000)
5691                 {
5692                         /*
5693                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5694                          * could result in non-forward-compatible dumps of WHEN clauses
5695                          * due to under-parenthesization.
5696                          */
5697                         appendPQExpBuffer(query,
5698                                                           "SELECT tgname, "
5699                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5700                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5701                                                           "tgenabled, tableoid, oid "
5702                                                           "FROM pg_catalog.pg_trigger t "
5703                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5704                                                           "AND NOT tgisinternal",
5705                                                           tbinfo->dobj.catId.oid);
5706                 }
5707                 else if (fout->remoteVersion >= 80300)
5708                 {
5709                         /*
5710                          * We ignore triggers that are tied to a foreign-key constraint
5711                          */
5712                         appendPQExpBuffer(query,
5713                                                           "SELECT tgname, "
5714                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5715                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5716                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5717                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5718                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5719                                                           "FROM pg_catalog.pg_trigger t "
5720                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5721                                                           "AND tgconstraint = 0",
5722                                                           tbinfo->dobj.catId.oid);
5723                 }
5724                 else if (fout->remoteVersion >= 70300)
5725                 {
5726                         /*
5727                          * We ignore triggers that are tied to a foreign-key constraint,
5728                          * but in these versions we have to grovel through pg_constraint
5729                          * to find out
5730                          */
5731                         appendPQExpBuffer(query,
5732                                                           "SELECT tgname, "
5733                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5734                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5735                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5736                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5737                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5738                                                           "FROM pg_catalog.pg_trigger t "
5739                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5740                                                           "AND (NOT tgisconstraint "
5741                                                           " OR NOT EXISTS"
5742                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5743                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5744                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5745                                                           tbinfo->dobj.catId.oid);
5746                 }
5747                 else if (fout->remoteVersion >= 70100)
5748                 {
5749                         appendPQExpBuffer(query,
5750                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5751                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5752                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5753                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5754                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5755                                                           "             AS tgconstrrelname "
5756                                                           "FROM pg_trigger "
5757                                                           "WHERE tgrelid = '%u'::oid",
5758                                                           tbinfo->dobj.catId.oid);
5759                 }
5760                 else
5761                 {
5762                         appendPQExpBuffer(query,
5763                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5764                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5765                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5766                                                           "tgconstrrelid, tginitdeferred, "
5767                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5768                                                           "oid, "
5769                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5770                                                           "             AS tgconstrrelname "
5771                                                           "FROM pg_trigger "
5772                                                           "WHERE tgrelid = '%u'::oid",
5773                                                           tbinfo->dobj.catId.oid);
5774                 }
5775                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5776
5777                 ntups = PQntuples(res);
5778
5779                 i_tableoid = PQfnumber(res, "tableoid");
5780                 i_oid = PQfnumber(res, "oid");
5781                 i_tgname = PQfnumber(res, "tgname");
5782                 i_tgfname = PQfnumber(res, "tgfname");
5783                 i_tgtype = PQfnumber(res, "tgtype");
5784                 i_tgnargs = PQfnumber(res, "tgnargs");
5785                 i_tgargs = PQfnumber(res, "tgargs");
5786                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5787                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5788                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5789                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5790                 i_tgenabled = PQfnumber(res, "tgenabled");
5791                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5792                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5793                 i_tgdef = PQfnumber(res, "tgdef");
5794
5795                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5796
5797                 for (j = 0; j < ntups; j++)
5798                 {
5799                         tginfo[j].dobj.objType = DO_TRIGGER;
5800                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5801                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5802                         AssignDumpId(&tginfo[j].dobj);
5803                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5804                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5805                         tginfo[j].tgtable = tbinfo;
5806                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5807                         if (i_tgdef >= 0)
5808                         {
5809                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5810
5811                                 /* remaining fields are not valid if we have tgdef */
5812                                 tginfo[j].tgfname = NULL;
5813                                 tginfo[j].tgtype = 0;
5814                                 tginfo[j].tgnargs = 0;
5815                                 tginfo[j].tgargs = NULL;
5816                                 tginfo[j].tgisconstraint = false;
5817                                 tginfo[j].tgdeferrable = false;
5818                                 tginfo[j].tginitdeferred = false;
5819                                 tginfo[j].tgconstrname = NULL;
5820                                 tginfo[j].tgconstrrelid = InvalidOid;
5821                                 tginfo[j].tgconstrrelname = NULL;
5822                         }
5823                         else
5824                         {
5825                                 tginfo[j].tgdef = NULL;
5826
5827                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5828                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5829                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5830                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5831                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5832                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5833                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5834
5835                                 if (tginfo[j].tgisconstraint)
5836                                 {
5837                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5838                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5839                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5840                                         {
5841                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5842                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5843                                                                                   tginfo[j].dobj.name,
5844                                                                                   tbinfo->dobj.name,
5845                                                                                   tginfo[j].tgconstrrelid);
5846                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5847                                         }
5848                                         else
5849                                                 tginfo[j].tgconstrrelname = NULL;
5850                                 }
5851                                 else
5852                                 {
5853                                         tginfo[j].tgconstrname = NULL;
5854                                         tginfo[j].tgconstrrelid = InvalidOid;
5855                                         tginfo[j].tgconstrrelname = NULL;
5856                                 }
5857                         }
5858                 }
5859
5860                 PQclear(res);
5861         }
5862
5863         destroyPQExpBuffer(query);
5864 }
5865
5866 /*
5867  * getEventTriggers
5868  *        get information about event triggers
5869  */
5870 EventTriggerInfo *
5871 getEventTriggers(Archive *fout, int *numEventTriggers)
5872 {
5873         int                     i;
5874         PQExpBuffer query;
5875         PGresult   *res;
5876         EventTriggerInfo *evtinfo;
5877         int                     i_tableoid,
5878                                 i_oid,
5879                                 i_evtname,
5880                                 i_evtevent,
5881                                 i_evtowner,
5882                                 i_evttags,
5883                                 i_evtfname,
5884                                 i_evtenabled;
5885         int                     ntups;
5886
5887         /* Before 9.3, there are no event triggers */
5888         if (fout->remoteVersion < 90300)
5889         {
5890                 *numEventTriggers = 0;
5891                 return NULL;
5892         }
5893
5894         query = createPQExpBuffer();
5895
5896         /* Make sure we are in proper schema */
5897         selectSourceSchema(fout, "pg_catalog");
5898
5899         appendPQExpBuffer(query,
5900                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5901                                           "evtevent, (%s evtowner) AS evtowner, "
5902                                           "array_to_string(array("
5903                                           "select quote_literal(x) "
5904                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5905                                           "e.evtfoid::regproc as evtfname "
5906                                           "FROM pg_event_trigger e "
5907                                           "ORDER BY e.oid",
5908                                           username_subquery);
5909
5910         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5911
5912         ntups = PQntuples(res);
5913
5914         *numEventTriggers = ntups;
5915
5916         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5917
5918         i_tableoid = PQfnumber(res, "tableoid");
5919         i_oid = PQfnumber(res, "oid");
5920         i_evtname = PQfnumber(res, "evtname");
5921         i_evtevent = PQfnumber(res, "evtevent");
5922         i_evtowner = PQfnumber(res, "evtowner");
5923         i_evttags = PQfnumber(res, "evttags");
5924         i_evtfname = PQfnumber(res, "evtfname");
5925         i_evtenabled = PQfnumber(res, "evtenabled");
5926
5927         for (i = 0; i < ntups; i++)
5928         {
5929                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5930                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5931                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5932                 AssignDumpId(&evtinfo[i].dobj);
5933                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5934                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5935                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5936                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5937                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5938                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5939                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5940         }
5941
5942         PQclear(res);
5943
5944         destroyPQExpBuffer(query);
5945
5946         return evtinfo;
5947 }
5948
5949 /*
5950  * getProcLangs
5951  *        get basic information about every procedural language in the system
5952  *
5953  * numProcLangs is set to the number of langs read in
5954  *
5955  * NB: this must run after getFuncs() because we assume we can do
5956  * findFuncByOid().
5957  */
5958 ProcLangInfo *
5959 getProcLangs(Archive *fout, int *numProcLangs)
5960 {
5961         PGresult   *res;
5962         int                     ntups;
5963         int                     i;
5964         PQExpBuffer query = createPQExpBuffer();
5965         ProcLangInfo *planginfo;
5966         int                     i_tableoid;
5967         int                     i_oid;
5968         int                     i_lanname;
5969         int                     i_lanpltrusted;
5970         int                     i_lanplcallfoid;
5971         int                     i_laninline;
5972         int                     i_lanvalidator;
5973         int                     i_lanacl;
5974         int                     i_lanowner;
5975
5976         /* Make sure we are in proper schema */
5977         selectSourceSchema(fout, "pg_catalog");
5978
5979         if (fout->remoteVersion >= 90000)
5980         {
5981                 /* pg_language has a laninline column */
5982                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5983                                                   "lanname, lanpltrusted, lanplcallfoid, "
5984                                                   "laninline, lanvalidator,  lanacl, "
5985                                                   "(%s lanowner) AS lanowner "
5986                                                   "FROM pg_language "
5987                                                   "WHERE lanispl "
5988                                                   "ORDER BY oid",
5989                                                   username_subquery);
5990         }
5991         else if (fout->remoteVersion >= 80300)
5992         {
5993                 /* pg_language has a lanowner column */
5994                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5995                                                   "lanname, lanpltrusted, lanplcallfoid, "
5996                                                   "lanvalidator,  lanacl, "
5997                                                   "(%s lanowner) AS lanowner "
5998                                                   "FROM pg_language "
5999                                                   "WHERE lanispl "
6000                                                   "ORDER BY oid",
6001                                                   username_subquery);
6002         }
6003         else if (fout->remoteVersion >= 80100)
6004         {
6005                 /* Languages are owned by the bootstrap superuser, OID 10 */
6006                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6007                                                   "(%s '10') AS lanowner "
6008                                                   "FROM pg_language "
6009                                                   "WHERE lanispl "
6010                                                   "ORDER BY oid",
6011                                                   username_subquery);
6012         }
6013         else if (fout->remoteVersion >= 70400)
6014         {
6015                 /* Languages are owned by the bootstrap superuser, sysid 1 */
6016                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6017                                                   "(%s '1') AS lanowner "
6018                                                   "FROM pg_language "
6019                                                   "WHERE lanispl "
6020                                                   "ORDER BY oid",
6021                                                   username_subquery);
6022         }
6023         else if (fout->remoteVersion >= 70100)
6024         {
6025                 /* No clear notion of an owner at all before 7.4 ... */
6026                 appendPQExpBufferStr(query, "SELECT tableoid, oid, * FROM pg_language "
6027                                                          "WHERE lanispl "
6028                                                          "ORDER BY oid");
6029         }
6030         else
6031         {
6032                 appendPQExpBufferStr(query, "SELECT "
6033                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
6034                                                          "oid, * FROM pg_language "
6035                                                          "WHERE lanispl "
6036                                                          "ORDER BY oid");
6037         }
6038
6039         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6040
6041         ntups = PQntuples(res);
6042
6043         *numProcLangs = ntups;
6044
6045         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
6046
6047         i_tableoid = PQfnumber(res, "tableoid");
6048         i_oid = PQfnumber(res, "oid");
6049         i_lanname = PQfnumber(res, "lanname");
6050         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
6051         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
6052         /* these may fail and return -1: */
6053         i_laninline = PQfnumber(res, "laninline");
6054         i_lanvalidator = PQfnumber(res, "lanvalidator");
6055         i_lanacl = PQfnumber(res, "lanacl");
6056         i_lanowner = PQfnumber(res, "lanowner");
6057
6058         for (i = 0; i < ntups; i++)
6059         {
6060                 planginfo[i].dobj.objType = DO_PROCLANG;
6061                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6062                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6063                 AssignDumpId(&planginfo[i].dobj);
6064
6065                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
6066                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
6067                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
6068                 if (i_laninline >= 0)
6069                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
6070                 else
6071                         planginfo[i].laninline = InvalidOid;
6072                 if (i_lanvalidator >= 0)
6073                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
6074                 else
6075                         planginfo[i].lanvalidator = InvalidOid;
6076                 if (i_lanacl >= 0)
6077                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
6078                 else
6079                         planginfo[i].lanacl = pg_strdup("{=U}");
6080                 if (i_lanowner >= 0)
6081                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
6082                 else
6083                         planginfo[i].lanowner = pg_strdup("");
6084
6085                 if (fout->remoteVersion < 70300)
6086                 {
6087                         /*
6088                          * We need to make a dependency to ensure the function will be
6089                          * dumped first.  (In 7.3 and later the regular dependency
6090                          * mechanism will handle this for us.)
6091                          */
6092                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
6093
6094                         if (funcInfo)
6095                                 addObjectDependency(&planginfo[i].dobj,
6096                                                                         funcInfo->dobj.dumpId);
6097                 }
6098         }
6099
6100         PQclear(res);
6101
6102         destroyPQExpBuffer(query);
6103
6104         return planginfo;
6105 }
6106
6107 /*
6108  * getCasts
6109  *        get basic information about every cast in the system
6110  *
6111  * numCasts is set to the number of casts read in
6112  */
6113 CastInfo *
6114 getCasts(Archive *fout, int *numCasts)
6115 {
6116         PGresult   *res;
6117         int                     ntups;
6118         int                     i;
6119         PQExpBuffer query = createPQExpBuffer();
6120         CastInfo   *castinfo;
6121         int                     i_tableoid;
6122         int                     i_oid;
6123         int                     i_castsource;
6124         int                     i_casttarget;
6125         int                     i_castfunc;
6126         int                     i_castcontext;
6127         int                     i_castmethod;
6128
6129         /* Make sure we are in proper schema */
6130         selectSourceSchema(fout, "pg_catalog");
6131
6132         if (fout->remoteVersion >= 80400)
6133         {
6134                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
6135                                                          "castsource, casttarget, castfunc, castcontext, "
6136                                                          "castmethod "
6137                                                          "FROM pg_cast ORDER BY 3,4");
6138         }
6139         else if (fout->remoteVersion >= 70300)
6140         {
6141                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
6142                                                          "castsource, casttarget, castfunc, castcontext, "
6143                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6144                                                          "FROM pg_cast ORDER BY 3,4");
6145         }
6146         else
6147         {
6148                 appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, "
6149                                                          "t1.oid AS castsource, t2.oid AS casttarget, "
6150                                                          "p.oid AS castfunc, 'e' AS castcontext, "
6151                                                          "'f' AS castmethod "
6152                                                          "FROM pg_type t1, pg_type t2, pg_proc p "
6153                                                          "WHERE p.pronargs = 1 AND "
6154                                                          "p.proargtypes[0] = t1.oid AND "
6155                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
6156                                                          "ORDER BY 3,4");
6157         }
6158
6159         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6160
6161         ntups = PQntuples(res);
6162
6163         *numCasts = ntups;
6164
6165         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6166
6167         i_tableoid = PQfnumber(res, "tableoid");
6168         i_oid = PQfnumber(res, "oid");
6169         i_castsource = PQfnumber(res, "castsource");
6170         i_casttarget = PQfnumber(res, "casttarget");
6171         i_castfunc = PQfnumber(res, "castfunc");
6172         i_castcontext = PQfnumber(res, "castcontext");
6173         i_castmethod = PQfnumber(res, "castmethod");
6174
6175         for (i = 0; i < ntups; i++)
6176         {
6177                 PQExpBufferData namebuf;
6178                 TypeInfo   *sTypeInfo;
6179                 TypeInfo   *tTypeInfo;
6180
6181                 castinfo[i].dobj.objType = DO_CAST;
6182                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6183                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6184                 AssignDumpId(&castinfo[i].dobj);
6185                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6186                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6187                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6188                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6189                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6190
6191                 /*
6192                  * Try to name cast as concatenation of typnames.  This is only used
6193                  * for purposes of sorting.  If we fail to find either type, the name
6194                  * will be an empty string.
6195                  */
6196                 initPQExpBuffer(&namebuf);
6197                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6198                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6199                 if (sTypeInfo && tTypeInfo)
6200                         appendPQExpBuffer(&namebuf, "%s %s",
6201                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6202                 castinfo[i].dobj.name = namebuf.data;
6203
6204                 if (OidIsValid(castinfo[i].castfunc))
6205                 {
6206                         /*
6207                          * We need to make a dependency to ensure the function will be
6208                          * dumped first.  (In 7.3 and later the regular dependency
6209                          * mechanism will handle this for us.)
6210                          */
6211                         FuncInfo   *funcInfo;
6212
6213                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6214                         if (funcInfo)
6215                                 addObjectDependency(&castinfo[i].dobj,
6216                                                                         funcInfo->dobj.dumpId);
6217                 }
6218         }
6219
6220         PQclear(res);
6221
6222         destroyPQExpBuffer(query);
6223
6224         return castinfo;
6225 }
6226
6227 /*
6228  * getTableAttrs -
6229  *        for each interesting table, read info about its attributes
6230  *        (names, types, default values, CHECK constraints, etc)
6231  *
6232  * This is implemented in a very inefficient way right now, looping
6233  * through the tblinfo and doing a join per table to find the attrs and their
6234  * types.  However, because we want type names and so forth to be named
6235  * relative to the schema of each table, we couldn't do it in just one
6236  * query.  (Maybe one query per schema?)
6237  *
6238  *      modifies tblinfo
6239  */
6240 void
6241 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
6242 {
6243         int                     i,
6244                                 j;
6245         PQExpBuffer q = createPQExpBuffer();
6246         int                     i_attnum;
6247         int                     i_attname;
6248         int                     i_atttypname;
6249         int                     i_atttypmod;
6250         int                     i_attstattarget;
6251         int                     i_attstorage;
6252         int                     i_typstorage;
6253         int                     i_attnotnull;
6254         int                     i_atthasdef;
6255         int                     i_attisdropped;
6256         int                     i_attlen;
6257         int                     i_attalign;
6258         int                     i_attislocal;
6259         int                     i_attoptions;
6260         int                     i_attcollation;
6261         int                     i_attfdwoptions;
6262         PGresult   *res;
6263         int                     ntups;
6264         bool            hasdefaults;
6265
6266         for (i = 0; i < numTables; i++)
6267         {
6268                 TableInfo  *tbinfo = &tblinfo[i];
6269
6270                 /* Don't bother to collect info for sequences */
6271                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6272                         continue;
6273
6274                 /* Don't bother with uninteresting tables, either */
6275                 if (!tbinfo->interesting)
6276                         continue;
6277
6278                 /*
6279                  * Make sure we are in proper schema for this table; this allows
6280                  * correct retrieval of formatted type names and default exprs
6281                  */
6282                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6283
6284                 /* find all the user attributes and their types */
6285
6286                 /*
6287                  * we must read the attribute names in attribute number order! because
6288                  * we will use the attnum to index into the attnames array later.  We
6289                  * actually ask to order by "attrelid, attnum" because (at least up to
6290                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6291                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6292                  */
6293                 if (g_verbose)
6294                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
6295                                           tbinfo->dobj.name);
6296
6297                 resetPQExpBuffer(q);
6298
6299                 if (fout->remoteVersion >= 90200)
6300                 {
6301                         /*
6302                          * attfdwoptions is new in 9.2.
6303                          */
6304                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6305                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6306                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6307                                                           "a.attlen, a.attalign, a.attislocal, "
6308                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6309                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6310                                                           "CASE WHEN a.attcollation <> t.typcollation "
6311                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6312                                                           "pg_catalog.array_to_string(ARRAY("
6313                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6314                                                           "' ' || pg_catalog.quote_literal(option_value) "
6315                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6316                                                           "ORDER BY option_name"
6317                                                           "), E',\n    ') AS attfdwoptions "
6318                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6319                                                           "ON a.atttypid = t.oid "
6320                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6321                                                           "AND a.attnum > 0::pg_catalog.int2 "
6322                                                           "ORDER BY a.attrelid, a.attnum",
6323                                                           tbinfo->dobj.catId.oid);
6324                 }
6325                 else if (fout->remoteVersion >= 90100)
6326                 {
6327                         /*
6328                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6329                          * clauses for attributes whose collation is different from their
6330                          * type's default, we use a CASE here to suppress uninteresting
6331                          * attcollations cheaply.
6332                          */
6333                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6334                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6335                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6336                                                           "a.attlen, a.attalign, a.attislocal, "
6337                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6338                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6339                                                           "CASE WHEN a.attcollation <> t.typcollation "
6340                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6341                                                           "NULL AS attfdwoptions "
6342                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6343                                                           "ON a.atttypid = t.oid "
6344                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6345                                                           "AND a.attnum > 0::pg_catalog.int2 "
6346                                                           "ORDER BY a.attrelid, a.attnum",
6347                                                           tbinfo->dobj.catId.oid);
6348                 }
6349                 else if (fout->remoteVersion >= 90000)
6350                 {
6351                         /* attoptions is new in 9.0 */
6352                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6353                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6354                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6355                                                           "a.attlen, a.attalign, a.attislocal, "
6356                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6357                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6358                                                           "0 AS attcollation, "
6359                                                           "NULL AS attfdwoptions "
6360                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6361                                                           "ON a.atttypid = t.oid "
6362                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6363                                                           "AND a.attnum > 0::pg_catalog.int2 "
6364                                                           "ORDER BY a.attrelid, a.attnum",
6365                                                           tbinfo->dobj.catId.oid);
6366                 }
6367                 else if (fout->remoteVersion >= 70300)
6368                 {
6369                         /* need left join here to not fail on dropped columns ... */
6370                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6371                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6372                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6373                                                           "a.attlen, a.attalign, a.attislocal, "
6374                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6375                                                           "'' AS attoptions, 0 AS attcollation, "
6376                                                           "NULL AS attfdwoptions "
6377                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6378                                                           "ON a.atttypid = t.oid "
6379                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6380                                                           "AND a.attnum > 0::pg_catalog.int2 "
6381                                                           "ORDER BY a.attrelid, a.attnum",
6382                                                           tbinfo->dobj.catId.oid);
6383                 }
6384                 else if (fout->remoteVersion >= 70100)
6385                 {
6386                         /*
6387                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6388                          * we don't dump it because we can't tell whether it's been
6389                          * explicitly set or was just a default.
6390                          *
6391                          * attislocal doesn't exist before 7.3, either; in older databases
6392                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6393                          */
6394                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6395                                                           "-1 AS attstattarget, a.attstorage, "
6396                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6397                                                           "false AS attisdropped, a.attlen, "
6398                                                           "a.attalign, true AS attislocal, "
6399                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6400                                                           "'' AS attoptions, 0 AS attcollation, "
6401                                                           "NULL AS attfdwoptions "
6402                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6403                                                           "ON a.atttypid = t.oid "
6404                                                           "WHERE a.attrelid = '%u'::oid "
6405                                                           "AND a.attnum > 0::int2 "
6406                                                           "ORDER BY a.attrelid, a.attnum",
6407                                                           tbinfo->dobj.catId.oid);
6408                 }
6409                 else
6410                 {
6411                         /* format_type not available before 7.1 */
6412                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6413                                                           "-1 AS attstattarget, "
6414                                                           "attstorage, attstorage AS typstorage, "
6415                                                           "attnotnull, atthasdef, false AS attisdropped, "
6416                                                           "attlen, attalign, "
6417                                                           "true AS attislocal, "
6418                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6419                                                           "'' AS attoptions, 0 AS attcollation, "
6420                                                           "NULL AS attfdwoptions "
6421                                                           "FROM pg_attribute a "
6422                                                           "WHERE attrelid = '%u'::oid "
6423                                                           "AND attnum > 0::int2 "
6424                                                           "ORDER BY attrelid, attnum",
6425                                                           tbinfo->dobj.catId.oid);
6426                 }
6427
6428                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6429
6430                 ntups = PQntuples(res);
6431
6432                 i_attnum = PQfnumber(res, "attnum");
6433                 i_attname = PQfnumber(res, "attname");
6434                 i_atttypname = PQfnumber(res, "atttypname");
6435                 i_atttypmod = PQfnumber(res, "atttypmod");
6436                 i_attstattarget = PQfnumber(res, "attstattarget");
6437                 i_attstorage = PQfnumber(res, "attstorage");
6438                 i_typstorage = PQfnumber(res, "typstorage");
6439                 i_attnotnull = PQfnumber(res, "attnotnull");
6440                 i_atthasdef = PQfnumber(res, "atthasdef");
6441                 i_attisdropped = PQfnumber(res, "attisdropped");
6442                 i_attlen = PQfnumber(res, "attlen");
6443                 i_attalign = PQfnumber(res, "attalign");
6444                 i_attislocal = PQfnumber(res, "attislocal");
6445                 i_attoptions = PQfnumber(res, "attoptions");
6446                 i_attcollation = PQfnumber(res, "attcollation");
6447                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6448
6449                 tbinfo->numatts = ntups;
6450                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6451                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6452                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6453                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6454                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6455                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6456                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6457                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6458                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6459                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6460                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6461                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6462                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6463                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6464                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6465                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6466                 hasdefaults = false;
6467
6468                 for (j = 0; j < ntups; j++)
6469                 {
6470                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6471                                 exit_horribly(NULL,
6472                                                           "invalid column numbering in table \"%s\"\n",
6473                                                           tbinfo->dobj.name);
6474                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6475                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6476                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6477                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6478                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6479                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6480                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6481                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6482                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6483                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6484                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6485                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6486                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6487                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6488                         tbinfo->attrdefs[j] = NULL; /* fix below */
6489                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6490                                 hasdefaults = true;
6491                         /* these flags will be set in flagInhAttrs() */
6492                         tbinfo->inhNotNull[j] = false;
6493                 }
6494
6495                 PQclear(res);
6496
6497                 /*
6498                  * Get info about column defaults
6499                  */
6500                 if (hasdefaults)
6501                 {
6502                         AttrDefInfo *attrdefs;
6503                         int                     numDefaults;
6504
6505                         if (g_verbose)
6506                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
6507                                                   tbinfo->dobj.name);
6508
6509                         resetPQExpBuffer(q);
6510                         if (fout->remoteVersion >= 70300)
6511                         {
6512                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6513                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6514                                                                   "FROM pg_catalog.pg_attrdef "
6515                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6516                                                                   tbinfo->dobj.catId.oid);
6517                         }
6518                         else if (fout->remoteVersion >= 70200)
6519                         {
6520                                 /* 7.2 did not have OIDs in pg_attrdef */
6521                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6522                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6523                                                                   "FROM pg_attrdef "
6524                                                                   "WHERE adrelid = '%u'::oid",
6525                                                                   tbinfo->dobj.catId.oid);
6526                         }
6527                         else if (fout->remoteVersion >= 70100)
6528                         {
6529                                 /* no pg_get_expr, so must rely on adsrc */
6530                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6531                                                                   "FROM pg_attrdef "
6532                                                                   "WHERE adrelid = '%u'::oid",
6533                                                                   tbinfo->dobj.catId.oid);
6534                         }
6535                         else
6536                         {
6537                                 /* no pg_get_expr, no tableoid either */
6538                                 appendPQExpBuffer(q, "SELECT "
6539                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6540                                                                   "oid, adnum, adsrc "
6541                                                                   "FROM pg_attrdef "
6542                                                                   "WHERE adrelid = '%u'::oid",
6543                                                                   tbinfo->dobj.catId.oid);
6544                         }
6545                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6546
6547                         numDefaults = PQntuples(res);
6548                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6549
6550                         for (j = 0; j < numDefaults; j++)
6551                         {
6552                                 int                     adnum;
6553
6554                                 adnum = atoi(PQgetvalue(res, j, 2));
6555
6556                                 if (adnum <= 0 || adnum > ntups)
6557                                         exit_horribly(NULL,
6558                                                                   "invalid adnum value %d for table \"%s\"\n",
6559                                                                   adnum, tbinfo->dobj.name);
6560
6561                                 /*
6562                                  * dropped columns shouldn't have defaults, but just in case,
6563                                  * ignore 'em
6564                                  */
6565                                 if (tbinfo->attisdropped[adnum - 1])
6566                                         continue;
6567
6568                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6569                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6570                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6571                                 AssignDumpId(&attrdefs[j].dobj);
6572                                 attrdefs[j].adtable = tbinfo;
6573                                 attrdefs[j].adnum = adnum;
6574                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6575
6576                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6577                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6578
6579                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6580
6581                                 /*
6582                                  * Defaults on a VIEW must always be dumped as separate ALTER
6583                                  * TABLE commands.  Defaults on regular tables are dumped as
6584                                  * part of the CREATE TABLE if possible, which it won't be if
6585                                  * the column is not going to be emitted explicitly.
6586                                  */
6587                                 if (tbinfo->relkind == RELKIND_VIEW)
6588                                 {
6589                                         attrdefs[j].separate = true;
6590                                         /* needed in case pre-7.3 DB: */
6591                                         addObjectDependency(&attrdefs[j].dobj,
6592                                                                                 tbinfo->dobj.dumpId);
6593                                 }
6594                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6595                                 {
6596                                         /* column will be suppressed, print default separately */
6597                                         attrdefs[j].separate = true;
6598                                         /* needed in case pre-7.3 DB: */
6599                                         addObjectDependency(&attrdefs[j].dobj,
6600                                                                                 tbinfo->dobj.dumpId);
6601                                 }
6602                                 else
6603                                 {
6604                                         attrdefs[j].separate = false;
6605
6606                                         /*
6607                                          * Mark the default as needing to appear before the table,
6608                                          * so that any dependencies it has must be emitted before
6609                                          * the CREATE TABLE.  If this is not possible, we'll
6610                                          * change to "separate" mode while sorting dependencies.
6611                                          */
6612                                         addObjectDependency(&tbinfo->dobj,
6613                                                                                 attrdefs[j].dobj.dumpId);
6614                                 }
6615
6616                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6617                         }
6618                         PQclear(res);
6619                 }
6620
6621                 /*
6622                  * Get info about table CHECK constraints
6623                  */
6624                 if (tbinfo->ncheck > 0)
6625                 {
6626                         ConstraintInfo *constrs;
6627                         int                     numConstrs;
6628
6629                         if (g_verbose)
6630                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6631                                                   tbinfo->dobj.name);
6632
6633                         resetPQExpBuffer(q);
6634                         if (fout->remoteVersion >= 90200)
6635                         {
6636                                 /*
6637                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6638                                  * but it wasn't ever false for check constraints until 9.2).
6639                                  */
6640                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6641                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6642                                                                   "conislocal, convalidated "
6643                                                                   "FROM pg_catalog.pg_constraint "
6644                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6645                                                                   "   AND contype = 'c' "
6646                                                                   "ORDER BY conname",
6647                                                                   tbinfo->dobj.catId.oid);
6648                         }
6649                         else if (fout->remoteVersion >= 80400)
6650                         {
6651                                 /* conislocal is new in 8.4 */
6652                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6653                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6654                                                                   "conislocal, true AS convalidated "
6655                                                                   "FROM pg_catalog.pg_constraint "
6656                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6657                                                                   "   AND contype = 'c' "
6658                                                                   "ORDER BY conname",
6659                                                                   tbinfo->dobj.catId.oid);
6660                         }
6661                         else if (fout->remoteVersion >= 70400)
6662                         {
6663                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6664                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6665                                                                   "true AS conislocal, true AS convalidated "
6666                                                                   "FROM pg_catalog.pg_constraint "
6667                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6668                                                                   "   AND contype = 'c' "
6669                                                                   "ORDER BY conname",
6670                                                                   tbinfo->dobj.catId.oid);
6671                         }
6672                         else if (fout->remoteVersion >= 70300)
6673                         {
6674                                 /* no pg_get_constraintdef, must use consrc */
6675                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6676                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6677                                                                   "true AS conislocal, true AS convalidated "
6678                                                                   "FROM pg_catalog.pg_constraint "
6679                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6680                                                                   "   AND contype = 'c' "
6681                                                                   "ORDER BY conname",
6682                                                                   tbinfo->dobj.catId.oid);
6683                         }
6684                         else if (fout->remoteVersion >= 70200)
6685                         {
6686                                 /* 7.2 did not have OIDs in pg_relcheck */
6687                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6688                                                                   "rcname AS conname, "
6689                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6690                                                                   "true AS conislocal, true AS convalidated "
6691                                                                   "FROM pg_relcheck "
6692                                                                   "WHERE rcrelid = '%u'::oid "
6693                                                                   "ORDER BY rcname",
6694                                                                   tbinfo->dobj.catId.oid);
6695                         }
6696                         else if (fout->remoteVersion >= 70100)
6697                         {
6698                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6699                                                                   "rcname AS conname, "
6700                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6701                                                                   "true AS conislocal, true AS convalidated "
6702                                                                   "FROM pg_relcheck "
6703                                                                   "WHERE rcrelid = '%u'::oid "
6704                                                                   "ORDER BY rcname",
6705                                                                   tbinfo->dobj.catId.oid);
6706                         }
6707                         else
6708                         {
6709                                 /* no tableoid in 7.0 */
6710                                 appendPQExpBuffer(q, "SELECT "
6711                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6712                                                                   "oid, rcname AS conname, "
6713                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6714                                                                   "true AS conislocal, true AS convalidated "
6715                                                                   "FROM pg_relcheck "
6716                                                                   "WHERE rcrelid = '%u'::oid "
6717                                                                   "ORDER BY rcname",
6718                                                                   tbinfo->dobj.catId.oid);
6719                         }
6720                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6721
6722                         numConstrs = PQntuples(res);
6723                         if (numConstrs != tbinfo->ncheck)
6724                         {
6725                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6726                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6727                                                                                  tbinfo->ncheck),
6728                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6729                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6730                                 exit_nicely(1);
6731                         }
6732
6733                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6734                         tbinfo->checkexprs = constrs;
6735
6736                         for (j = 0; j < numConstrs; j++)
6737                         {
6738                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6739
6740                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6741                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6742                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6743                                 AssignDumpId(&constrs[j].dobj);
6744                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6745                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6746                                 constrs[j].contable = tbinfo;
6747                                 constrs[j].condomain = NULL;
6748                                 constrs[j].contype = 'c';
6749                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6750                                 constrs[j].confrelid = InvalidOid;
6751                                 constrs[j].conindex = 0;
6752                                 constrs[j].condeferrable = false;
6753                                 constrs[j].condeferred = false;
6754                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6755
6756                                 /*
6757                                  * An unvalidated constraint needs to be dumped separately, so
6758                                  * that potentially-violating existing data is loaded before
6759                                  * the constraint.
6760                                  */
6761                                 constrs[j].separate = !validated;
6762
6763                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6764
6765                                 /*
6766                                  * Mark the constraint as needing to appear before the table
6767                                  * --- this is so that any other dependencies of the
6768                                  * constraint will be emitted before we try to create the
6769                                  * table.  If the constraint is to be dumped separately, it
6770                                  * will be dumped after data is loaded anyway, so don't do it.
6771                                  * (There's an automatic dependency in the opposite direction
6772                                  * anyway, so don't need to add one manually here.)
6773                                  */
6774                                 if (!constrs[j].separate)
6775                                         addObjectDependency(&tbinfo->dobj,
6776                                                                                 constrs[j].dobj.dumpId);
6777
6778                                 /*
6779                                  * If the constraint is inherited, this will be detected later
6780                                  * (in pre-8.4 databases).  We also detect later if the
6781                                  * constraint must be split out from the table definition.
6782                                  */
6783                         }
6784                         PQclear(res);
6785                 }
6786         }
6787
6788         destroyPQExpBuffer(q);
6789 }
6790
6791 /*
6792  * Test whether a column should be printed as part of table's CREATE TABLE.
6793  * Column number is zero-based.
6794  *
6795  * Normally this is always true, but it's false for dropped columns, as well
6796  * as those that were inherited without any local definition.  (If we print
6797  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6798  * However, in binary_upgrade mode, we must print all such columns anyway and
6799  * fix the attislocal/attisdropped state later, so as to keep control of the
6800  * physical column order.
6801  *
6802  * This function exists because there are scattered nonobvious places that
6803  * must be kept in sync with this decision.
6804  */
6805 bool
6806 shouldPrintColumn(TableInfo *tbinfo, int colno)
6807 {
6808         if (binary_upgrade)
6809                 return true;
6810         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6811 }
6812
6813
6814 /*
6815  * getTSParsers:
6816  *        read all text search parsers in the system catalogs and return them
6817  *        in the TSParserInfo* structure
6818  *
6819  *      numTSParsers is set to the number of parsers read in
6820  */
6821 TSParserInfo *
6822 getTSParsers(Archive *fout, int *numTSParsers)
6823 {
6824         PGresult   *res;
6825         int                     ntups;
6826         int                     i;
6827         PQExpBuffer query;
6828         TSParserInfo *prsinfo;
6829         int                     i_tableoid;
6830         int                     i_oid;
6831         int                     i_prsname;
6832         int                     i_prsnamespace;
6833         int                     i_prsstart;
6834         int                     i_prstoken;
6835         int                     i_prsend;
6836         int                     i_prsheadline;
6837         int                     i_prslextype;
6838
6839         /* Before 8.3, there is no built-in text search support */
6840         if (fout->remoteVersion < 80300)
6841         {
6842                 *numTSParsers = 0;
6843                 return NULL;
6844         }
6845
6846         query = createPQExpBuffer();
6847
6848         /*
6849          * find all text search objects, including builtin ones; we filter out
6850          * system-defined objects at dump-out time.
6851          */
6852
6853         /* Make sure we are in proper schema */
6854         selectSourceSchema(fout, "pg_catalog");
6855
6856         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6857                                                  "prsstart::oid, prstoken::oid, "
6858                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
6859                                                  "FROM pg_ts_parser");
6860
6861         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6862
6863         ntups = PQntuples(res);
6864         *numTSParsers = ntups;
6865
6866         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6867
6868         i_tableoid = PQfnumber(res, "tableoid");
6869         i_oid = PQfnumber(res, "oid");
6870         i_prsname = PQfnumber(res, "prsname");
6871         i_prsnamespace = PQfnumber(res, "prsnamespace");
6872         i_prsstart = PQfnumber(res, "prsstart");
6873         i_prstoken = PQfnumber(res, "prstoken");
6874         i_prsend = PQfnumber(res, "prsend");
6875         i_prsheadline = PQfnumber(res, "prsheadline");
6876         i_prslextype = PQfnumber(res, "prslextype");
6877
6878         for (i = 0; i < ntups; i++)
6879         {
6880                 prsinfo[i].dobj.objType = DO_TSPARSER;
6881                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6882                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6883                 AssignDumpId(&prsinfo[i].dobj);
6884                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6885                 prsinfo[i].dobj.namespace =
6886                         findNamespace(fout,
6887                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6888                                                   prsinfo[i].dobj.catId.oid);
6889                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6890                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6891                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6892                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6893                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6894
6895                 /* Decide whether we want to dump it */
6896                 selectDumpableObject(&(prsinfo[i].dobj));
6897         }
6898
6899         PQclear(res);
6900
6901         destroyPQExpBuffer(query);
6902
6903         return prsinfo;
6904 }
6905
6906 /*
6907  * getTSDictionaries:
6908  *        read all text search dictionaries in the system catalogs and return them
6909  *        in the TSDictInfo* structure
6910  *
6911  *      numTSDicts is set to the number of dictionaries read in
6912  */
6913 TSDictInfo *
6914 getTSDictionaries(Archive *fout, int *numTSDicts)
6915 {
6916         PGresult   *res;
6917         int                     ntups;
6918         int                     i;
6919         PQExpBuffer query;
6920         TSDictInfo *dictinfo;
6921         int                     i_tableoid;
6922         int                     i_oid;
6923         int                     i_dictname;
6924         int                     i_dictnamespace;
6925         int                     i_rolname;
6926         int                     i_dicttemplate;
6927         int                     i_dictinitoption;
6928
6929         /* Before 8.3, there is no built-in text search support */
6930         if (fout->remoteVersion < 80300)
6931         {
6932                 *numTSDicts = 0;
6933                 return NULL;
6934         }
6935
6936         query = createPQExpBuffer();
6937
6938         /* Make sure we are in proper schema */
6939         selectSourceSchema(fout, "pg_catalog");
6940
6941         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6942                                           "dictnamespace, (%s dictowner) AS rolname, "
6943                                           "dicttemplate, dictinitoption "
6944                                           "FROM pg_ts_dict",
6945                                           username_subquery);
6946
6947         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6948
6949         ntups = PQntuples(res);
6950         *numTSDicts = ntups;
6951
6952         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6953
6954         i_tableoid = PQfnumber(res, "tableoid");
6955         i_oid = PQfnumber(res, "oid");
6956         i_dictname = PQfnumber(res, "dictname");
6957         i_dictnamespace = PQfnumber(res, "dictnamespace");
6958         i_rolname = PQfnumber(res, "rolname");
6959         i_dictinitoption = PQfnumber(res, "dictinitoption");
6960         i_dicttemplate = PQfnumber(res, "dicttemplate");
6961
6962         for (i = 0; i < ntups; i++)
6963         {
6964                 dictinfo[i].dobj.objType = DO_TSDICT;
6965                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6966                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6967                 AssignDumpId(&dictinfo[i].dobj);
6968                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6969                 dictinfo[i].dobj.namespace =
6970                         findNamespace(fout,
6971                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6972                                                   dictinfo[i].dobj.catId.oid);
6973                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6974                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6975                 if (PQgetisnull(res, i, i_dictinitoption))
6976                         dictinfo[i].dictinitoption = NULL;
6977                 else
6978                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6979
6980                 /* Decide whether we want to dump it */
6981                 selectDumpableObject(&(dictinfo[i].dobj));
6982         }
6983
6984         PQclear(res);
6985
6986         destroyPQExpBuffer(query);
6987
6988         return dictinfo;
6989 }
6990
6991 /*
6992  * getTSTemplates:
6993  *        read all text search templates in the system catalogs and return them
6994  *        in the TSTemplateInfo* structure
6995  *
6996  *      numTSTemplates is set to the number of templates read in
6997  */
6998 TSTemplateInfo *
6999 getTSTemplates(Archive *fout, int *numTSTemplates)
7000 {
7001         PGresult   *res;
7002         int                     ntups;
7003         int                     i;
7004         PQExpBuffer query;
7005         TSTemplateInfo *tmplinfo;
7006         int                     i_tableoid;
7007         int                     i_oid;
7008         int                     i_tmplname;
7009         int                     i_tmplnamespace;
7010         int                     i_tmplinit;
7011         int                     i_tmpllexize;
7012
7013         /* Before 8.3, there is no built-in text search support */
7014         if (fout->remoteVersion < 80300)
7015         {
7016                 *numTSTemplates = 0;
7017                 return NULL;
7018         }
7019
7020         query = createPQExpBuffer();
7021
7022         /* Make sure we are in proper schema */
7023         selectSourceSchema(fout, "pg_catalog");
7024
7025         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
7026                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
7027                                                  "FROM pg_ts_template");
7028
7029         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7030
7031         ntups = PQntuples(res);
7032         *numTSTemplates = ntups;
7033
7034         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
7035
7036         i_tableoid = PQfnumber(res, "tableoid");
7037         i_oid = PQfnumber(res, "oid");
7038         i_tmplname = PQfnumber(res, "tmplname");
7039         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
7040         i_tmplinit = PQfnumber(res, "tmplinit");
7041         i_tmpllexize = PQfnumber(res, "tmpllexize");
7042
7043         for (i = 0; i < ntups; i++)
7044         {
7045                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
7046                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7047                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7048                 AssignDumpId(&tmplinfo[i].dobj);
7049                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
7050                 tmplinfo[i].dobj.namespace =
7051                         findNamespace(fout,
7052                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
7053                                                   tmplinfo[i].dobj.catId.oid);
7054                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
7055                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
7056
7057                 /* Decide whether we want to dump it */
7058                 selectDumpableObject(&(tmplinfo[i].dobj));
7059         }
7060
7061         PQclear(res);
7062
7063         destroyPQExpBuffer(query);
7064
7065         return tmplinfo;
7066 }
7067
7068 /*
7069  * getTSConfigurations:
7070  *        read all text search configurations in the system catalogs and return
7071  *        them in the TSConfigInfo* structure
7072  *
7073  *      numTSConfigs is set to the number of configurations read in
7074  */
7075 TSConfigInfo *
7076 getTSConfigurations(Archive *fout, int *numTSConfigs)
7077 {
7078         PGresult   *res;
7079         int                     ntups;
7080         int                     i;
7081         PQExpBuffer query;
7082         TSConfigInfo *cfginfo;
7083         int                     i_tableoid;
7084         int                     i_oid;
7085         int                     i_cfgname;
7086         int                     i_cfgnamespace;
7087         int                     i_rolname;
7088         int                     i_cfgparser;
7089
7090         /* Before 8.3, there is no built-in text search support */
7091         if (fout->remoteVersion < 80300)
7092         {
7093                 *numTSConfigs = 0;
7094                 return NULL;
7095         }
7096
7097         query = createPQExpBuffer();
7098
7099         /* Make sure we are in proper schema */
7100         selectSourceSchema(fout, "pg_catalog");
7101
7102         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
7103                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
7104                                           "FROM pg_ts_config",
7105                                           username_subquery);
7106
7107         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7108
7109         ntups = PQntuples(res);
7110         *numTSConfigs = ntups;
7111
7112         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
7113
7114         i_tableoid = PQfnumber(res, "tableoid");
7115         i_oid = PQfnumber(res, "oid");
7116         i_cfgname = PQfnumber(res, "cfgname");
7117         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
7118         i_rolname = PQfnumber(res, "rolname");
7119         i_cfgparser = PQfnumber(res, "cfgparser");
7120
7121         for (i = 0; i < ntups; i++)
7122         {
7123                 cfginfo[i].dobj.objType = DO_TSCONFIG;
7124                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7125                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7126                 AssignDumpId(&cfginfo[i].dobj);
7127                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
7128                 cfginfo[i].dobj.namespace =
7129                         findNamespace(fout,
7130                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
7131                                                   cfginfo[i].dobj.catId.oid);
7132                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7133                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7134
7135                 /* Decide whether we want to dump it */
7136                 selectDumpableObject(&(cfginfo[i].dobj));
7137         }
7138
7139         PQclear(res);
7140
7141         destroyPQExpBuffer(query);
7142
7143         return cfginfo;
7144 }
7145
7146 /*
7147  * getForeignDataWrappers:
7148  *        read all foreign-data wrappers in the system catalogs and return
7149  *        them in the FdwInfo* structure
7150  *
7151  *      numForeignDataWrappers is set to the number of fdws read in
7152  */
7153 FdwInfo *
7154 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7155 {
7156         PGresult   *res;
7157         int                     ntups;
7158         int                     i;
7159         PQExpBuffer query;
7160         FdwInfo    *fdwinfo;
7161         int                     i_tableoid;
7162         int                     i_oid;
7163         int                     i_fdwname;
7164         int                     i_rolname;
7165         int                     i_fdwhandler;
7166         int                     i_fdwvalidator;
7167         int                     i_fdwacl;
7168         int                     i_fdwoptions;
7169
7170         /* Before 8.4, there are no foreign-data wrappers */
7171         if (fout->remoteVersion < 80400)
7172         {
7173                 *numForeignDataWrappers = 0;
7174                 return NULL;
7175         }
7176
7177         query = createPQExpBuffer();
7178
7179         /* Make sure we are in proper schema */
7180         selectSourceSchema(fout, "pg_catalog");
7181
7182         if (fout->remoteVersion >= 90100)
7183         {
7184                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7185                                                   "(%s fdwowner) AS rolname, "
7186                                                   "fdwhandler::pg_catalog.regproc, "
7187                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7188                                                   "array_to_string(ARRAY("
7189                                                   "SELECT quote_ident(option_name) || ' ' || "
7190                                                   "quote_literal(option_value) "
7191                                                   "FROM pg_options_to_table(fdwoptions) "
7192                                                   "ORDER BY option_name"
7193                                                   "), E',\n    ') AS fdwoptions "
7194                                                   "FROM pg_foreign_data_wrapper",
7195                                                   username_subquery);
7196         }
7197         else
7198         {
7199                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7200                                                   "(%s fdwowner) AS rolname, "
7201                                                   "'-' AS fdwhandler, "
7202                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7203                                                   "array_to_string(ARRAY("
7204                                                   "SELECT quote_ident(option_name) || ' ' || "
7205                                                   "quote_literal(option_value) "
7206                                                   "FROM pg_options_to_table(fdwoptions) "
7207                                                   "ORDER BY option_name"
7208                                                   "), E',\n    ') AS fdwoptions "
7209                                                   "FROM pg_foreign_data_wrapper",
7210                                                   username_subquery);
7211         }
7212
7213         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7214
7215         ntups = PQntuples(res);
7216         *numForeignDataWrappers = ntups;
7217
7218         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7219
7220         i_tableoid = PQfnumber(res, "tableoid");
7221         i_oid = PQfnumber(res, "oid");
7222         i_fdwname = PQfnumber(res, "fdwname");
7223         i_rolname = PQfnumber(res, "rolname");
7224         i_fdwhandler = PQfnumber(res, "fdwhandler");
7225         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7226         i_fdwacl = PQfnumber(res, "fdwacl");
7227         i_fdwoptions = PQfnumber(res, "fdwoptions");
7228
7229         for (i = 0; i < ntups; i++)
7230         {
7231                 fdwinfo[i].dobj.objType = DO_FDW;
7232                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7233                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7234                 AssignDumpId(&fdwinfo[i].dobj);
7235                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7236                 fdwinfo[i].dobj.namespace = NULL;
7237                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7238                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7239                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7240                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7241                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7242
7243                 /* Decide whether we want to dump it */
7244                 selectDumpableObject(&(fdwinfo[i].dobj));
7245         }
7246
7247         PQclear(res);
7248
7249         destroyPQExpBuffer(query);
7250
7251         return fdwinfo;
7252 }
7253
7254 /*
7255  * getForeignServers:
7256  *        read all foreign servers in the system catalogs and return
7257  *        them in the ForeignServerInfo * structure
7258  *
7259  *      numForeignServers is set to the number of servers read in
7260  */
7261 ForeignServerInfo *
7262 getForeignServers(Archive *fout, int *numForeignServers)
7263 {
7264         PGresult   *res;
7265         int                     ntups;
7266         int                     i;
7267         PQExpBuffer query;
7268         ForeignServerInfo *srvinfo;
7269         int                     i_tableoid;
7270         int                     i_oid;
7271         int                     i_srvname;
7272         int                     i_rolname;
7273         int                     i_srvfdw;
7274         int                     i_srvtype;
7275         int                     i_srvversion;
7276         int                     i_srvacl;
7277         int                     i_srvoptions;
7278
7279         /* Before 8.4, there are no foreign servers */
7280         if (fout->remoteVersion < 80400)
7281         {
7282                 *numForeignServers = 0;
7283                 return NULL;
7284         }
7285
7286         query = createPQExpBuffer();
7287
7288         /* Make sure we are in proper schema */
7289         selectSourceSchema(fout, "pg_catalog");
7290
7291         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7292                                           "(%s srvowner) AS rolname, "
7293                                           "srvfdw, srvtype, srvversion, srvacl,"
7294                                           "array_to_string(ARRAY("
7295                                           "SELECT quote_ident(option_name) || ' ' || "
7296                                           "quote_literal(option_value) "
7297                                           "FROM pg_options_to_table(srvoptions) "
7298                                           "ORDER BY option_name"
7299                                           "), E',\n    ') AS srvoptions "
7300                                           "FROM pg_foreign_server",
7301                                           username_subquery);
7302
7303         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7304
7305         ntups = PQntuples(res);
7306         *numForeignServers = ntups;
7307
7308         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7309
7310         i_tableoid = PQfnumber(res, "tableoid");
7311         i_oid = PQfnumber(res, "oid");
7312         i_srvname = PQfnumber(res, "srvname");
7313         i_rolname = PQfnumber(res, "rolname");
7314         i_srvfdw = PQfnumber(res, "srvfdw");
7315         i_srvtype = PQfnumber(res, "srvtype");
7316         i_srvversion = PQfnumber(res, "srvversion");
7317         i_srvacl = PQfnumber(res, "srvacl");
7318         i_srvoptions = PQfnumber(res, "srvoptions");
7319
7320         for (i = 0; i < ntups; i++)
7321         {
7322                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7323                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7324                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7325                 AssignDumpId(&srvinfo[i].dobj);
7326                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7327                 srvinfo[i].dobj.namespace = NULL;
7328                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7329                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7330                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7331                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7332                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7333                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7334
7335                 /* Decide whether we want to dump it */
7336                 selectDumpableObject(&(srvinfo[i].dobj));
7337         }
7338
7339         PQclear(res);
7340
7341         destroyPQExpBuffer(query);
7342
7343         return srvinfo;
7344 }
7345
7346 /*
7347  * getDefaultACLs:
7348  *        read all default ACL information in the system catalogs and return
7349  *        them in the DefaultACLInfo structure
7350  *
7351  *      numDefaultACLs is set to the number of ACLs read in
7352  */
7353 DefaultACLInfo *
7354 getDefaultACLs(Archive *fout, int *numDefaultACLs)
7355 {
7356         DefaultACLInfo *daclinfo;
7357         PQExpBuffer query;
7358         PGresult   *res;
7359         int                     i_oid;
7360         int                     i_tableoid;
7361         int                     i_defaclrole;
7362         int                     i_defaclnamespace;
7363         int                     i_defaclobjtype;
7364         int                     i_defaclacl;
7365         int                     i,
7366                                 ntups;
7367
7368         if (fout->remoteVersion < 90000)
7369         {
7370                 *numDefaultACLs = 0;
7371                 return NULL;
7372         }
7373
7374         query = createPQExpBuffer();
7375
7376         /* Make sure we are in proper schema */
7377         selectSourceSchema(fout, "pg_catalog");
7378
7379         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7380                                           "(%s defaclrole) AS defaclrole, "
7381                                           "defaclnamespace, "
7382                                           "defaclobjtype, "
7383                                           "defaclacl "
7384                                           "FROM pg_default_acl",
7385                                           username_subquery);
7386
7387         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7388
7389         ntups = PQntuples(res);
7390         *numDefaultACLs = ntups;
7391
7392         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7393
7394         i_oid = PQfnumber(res, "oid");
7395         i_tableoid = PQfnumber(res, "tableoid");
7396         i_defaclrole = PQfnumber(res, "defaclrole");
7397         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7398         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7399         i_defaclacl = PQfnumber(res, "defaclacl");
7400
7401         for (i = 0; i < ntups; i++)
7402         {
7403                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7404
7405                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7406                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7407                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7408                 AssignDumpId(&daclinfo[i].dobj);
7409                 /* cheesy ... is it worth coming up with a better object name? */
7410                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7411
7412                 if (nspid != InvalidOid)
7413                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7414                                                                                                  daclinfo[i].dobj.catId.oid);
7415                 else
7416                         daclinfo[i].dobj.namespace = NULL;
7417
7418                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7419                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7420                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7421
7422                 /* Decide whether we want to dump it */
7423                 selectDumpableDefaultACL(&(daclinfo[i]));
7424         }
7425
7426         PQclear(res);
7427
7428         destroyPQExpBuffer(query);
7429
7430         return daclinfo;
7431 }
7432
7433 /*
7434  * dumpComment --
7435  *
7436  * This routine is used to dump any comments associated with the
7437  * object handed to this routine. The routine takes a constant character
7438  * string for the target part of the comment-creation command, plus
7439  * the namespace and owner of the object (for labeling the ArchiveEntry),
7440  * plus catalog ID and subid which are the lookup key for pg_description,
7441  * plus the dump ID for the object (for setting a dependency).
7442  * If a matching pg_description entry is found, it is dumped.
7443  *
7444  * Note: although this routine takes a dumpId for dependency purposes,
7445  * that purpose is just to mark the dependency in the emitted dump file
7446  * for possible future use by pg_restore.  We do NOT use it for determining
7447  * ordering of the comment in the dump file, because this routine is called
7448  * after dependency sorting occurs.  This routine should be called just after
7449  * calling ArchiveEntry() for the specified object.
7450  */
7451 static void
7452 dumpComment(Archive *fout, const char *target,
7453                         const char *namespace, const char *owner,
7454                         CatalogId catalogId, int subid, DumpId dumpId)
7455 {
7456         CommentItem *comments;
7457         int                     ncomments;
7458
7459         /* Comments are schema not data ... except blob comments are data */
7460         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7461         {
7462                 if (dataOnly)
7463                         return;
7464         }
7465         else
7466         {
7467                 if (schemaOnly)
7468                         return;
7469         }
7470
7471         /* Search for comments associated with catalogId, using table */
7472         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7473                                                          &comments);
7474
7475         /* Is there one matching the subid? */
7476         while (ncomments > 0)
7477         {
7478                 if (comments->objsubid == subid)
7479                         break;
7480                 comments++;
7481                 ncomments--;
7482         }
7483
7484         /* If a comment exists, build COMMENT ON statement */
7485         if (ncomments > 0)
7486         {
7487                 PQExpBuffer query = createPQExpBuffer();
7488
7489                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7490                 appendStringLiteralAH(query, comments->descr, fout);
7491                 appendPQExpBufferStr(query, ";\n");
7492
7493                 /*
7494                  * We mark comments as SECTION_NONE because they really belong in the
7495                  * same section as their parent, whether that is pre-data or
7496                  * post-data.
7497                  */
7498                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7499                                          target, namespace, NULL, owner,
7500                                          false, "COMMENT", SECTION_NONE,
7501                                          query->data, "", NULL,
7502                                          &(dumpId), 1,
7503                                          NULL, NULL);
7504
7505                 destroyPQExpBuffer(query);
7506         }
7507 }
7508
7509 /*
7510  * dumpTableComment --
7511  *
7512  * As above, but dump comments for both the specified table (or view)
7513  * and its columns.
7514  */
7515 static void
7516 dumpTableComment(Archive *fout, TableInfo *tbinfo,
7517                                  const char *reltypename)
7518 {
7519         CommentItem *comments;
7520         int                     ncomments;
7521         PQExpBuffer query;
7522         PQExpBuffer target;
7523
7524         /* Comments are SCHEMA not data */
7525         if (dataOnly)
7526                 return;
7527
7528         /* Search for comments associated with relation, using table */
7529         ncomments = findComments(fout,
7530                                                          tbinfo->dobj.catId.tableoid,
7531                                                          tbinfo->dobj.catId.oid,
7532                                                          &comments);
7533
7534         /* If comments exist, build COMMENT ON statements */
7535         if (ncomments <= 0)
7536                 return;
7537
7538         query = createPQExpBuffer();
7539         target = createPQExpBuffer();
7540
7541         while (ncomments > 0)
7542         {
7543                 const char *descr = comments->descr;
7544                 int                     objsubid = comments->objsubid;
7545
7546                 if (objsubid == 0)
7547                 {
7548                         resetPQExpBuffer(target);
7549                         appendPQExpBuffer(target, "%s %s", reltypename,
7550                                                           fmtId(tbinfo->dobj.name));
7551
7552                         resetPQExpBuffer(query);
7553                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7554                         appendStringLiteralAH(query, descr, fout);
7555                         appendPQExpBufferStr(query, ";\n");
7556
7557                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7558                                                  target->data,
7559                                                  tbinfo->dobj.namespace->dobj.name,
7560                                                  NULL, tbinfo->rolname,
7561                                                  false, "COMMENT", SECTION_NONE,
7562                                                  query->data, "", NULL,
7563                                                  &(tbinfo->dobj.dumpId), 1,
7564                                                  NULL, NULL);
7565                 }
7566                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7567                 {
7568                         resetPQExpBuffer(target);
7569                         appendPQExpBuffer(target, "COLUMN %s.",
7570                                                           fmtId(tbinfo->dobj.name));
7571                         appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1]));
7572
7573                         resetPQExpBuffer(query);
7574                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7575                         appendStringLiteralAH(query, descr, fout);
7576                         appendPQExpBufferStr(query, ";\n");
7577
7578                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7579                                                  target->data,
7580                                                  tbinfo->dobj.namespace->dobj.name,
7581                                                  NULL, tbinfo->rolname,
7582                                                  false, "COMMENT", SECTION_NONE,
7583                                                  query->data, "", NULL,
7584                                                  &(tbinfo->dobj.dumpId), 1,
7585                                                  NULL, NULL);
7586                 }
7587
7588                 comments++;
7589                 ncomments--;
7590         }
7591
7592         destroyPQExpBuffer(query);
7593         destroyPQExpBuffer(target);
7594 }
7595
7596 /*
7597  * findComments --
7598  *
7599  * Find the comment(s), if any, associated with the given object.  All the
7600  * objsubid values associated with the given classoid/objoid are found with
7601  * one search.
7602  */
7603 static int
7604 findComments(Archive *fout, Oid classoid, Oid objoid,
7605                          CommentItem **items)
7606 {
7607         /* static storage for table of comments */
7608         static CommentItem *comments = NULL;
7609         static int      ncomments = -1;
7610
7611         CommentItem *middle = NULL;
7612         CommentItem *low;
7613         CommentItem *high;
7614         int                     nmatch;
7615
7616         /* Get comments if we didn't already */
7617         if (ncomments < 0)
7618                 ncomments = collectComments(fout, &comments);
7619
7620         /*
7621          * Pre-7.2, pg_description does not contain classoid, so collectComments
7622          * just stores a zero.  If there's a collision on object OID, well, you
7623          * get duplicate comments.
7624          */
7625         if (fout->remoteVersion < 70200)
7626                 classoid = 0;
7627
7628         /*
7629          * Do binary search to find some item matching the object.
7630          */
7631         low = &comments[0];
7632         high = &comments[ncomments - 1];
7633         while (low <= high)
7634         {
7635                 middle = low + (high - low) / 2;
7636
7637                 if (classoid < middle->classoid)
7638                         high = middle - 1;
7639                 else if (classoid > middle->classoid)
7640                         low = middle + 1;
7641                 else if (objoid < middle->objoid)
7642                         high = middle - 1;
7643                 else if (objoid > middle->objoid)
7644                         low = middle + 1;
7645                 else
7646                         break;                          /* found a match */
7647         }
7648
7649         if (low > high)                         /* no matches */
7650         {
7651                 *items = NULL;
7652                 return 0;
7653         }
7654
7655         /*
7656          * Now determine how many items match the object.  The search loop
7657          * invariant still holds: only items between low and high inclusive could
7658          * match.
7659          */
7660         nmatch = 1;
7661         while (middle > low)
7662         {
7663                 if (classoid != middle[-1].classoid ||
7664                         objoid != middle[-1].objoid)
7665                         break;
7666                 middle--;
7667                 nmatch++;
7668         }
7669
7670         *items = middle;
7671
7672         middle += nmatch;
7673         while (middle <= high)
7674         {
7675                 if (classoid != middle->classoid ||
7676                         objoid != middle->objoid)
7677                         break;
7678                 middle++;
7679                 nmatch++;
7680         }
7681
7682         return nmatch;
7683 }
7684
7685 /*
7686  * collectComments --
7687  *
7688  * Construct a table of all comments available for database objects.
7689  * We used to do per-object queries for the comments, but it's much faster
7690  * to pull them all over at once, and on most databases the memory cost
7691  * isn't high.
7692  *
7693  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7694  */
7695 static int
7696 collectComments(Archive *fout, CommentItem **items)
7697 {
7698         PGresult   *res;
7699         PQExpBuffer query;
7700         int                     i_description;
7701         int                     i_classoid;
7702         int                     i_objoid;
7703         int                     i_objsubid;
7704         int                     ntups;
7705         int                     i;
7706         CommentItem *comments;
7707
7708         /*
7709          * Note we do NOT change source schema here; preserve the caller's
7710          * setting, instead.
7711          */
7712
7713         query = createPQExpBuffer();
7714
7715         if (fout->remoteVersion >= 70300)
7716         {
7717                 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
7718                                                          "FROM pg_catalog.pg_description "
7719                                                          "ORDER BY classoid, objoid, objsubid");
7720         }
7721         else if (fout->remoteVersion >= 70200)
7722         {
7723                 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
7724                                                          "FROM pg_description "
7725                                                          "ORDER BY classoid, objoid, objsubid");
7726         }
7727         else
7728         {
7729                 /* Note: this will fail to find attribute comments in pre-7.2... */
7730                 appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7731                                                          "FROM pg_description "
7732                                                          "ORDER BY objoid");
7733         }
7734
7735         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7736
7737         /* Construct lookup table containing OIDs in numeric form */
7738
7739         i_description = PQfnumber(res, "description");
7740         i_classoid = PQfnumber(res, "classoid");
7741         i_objoid = PQfnumber(res, "objoid");
7742         i_objsubid = PQfnumber(res, "objsubid");
7743
7744         ntups = PQntuples(res);
7745
7746         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7747
7748         for (i = 0; i < ntups; i++)
7749         {
7750                 comments[i].descr = PQgetvalue(res, i, i_description);
7751                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7752                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7753                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7754         }
7755
7756         /* Do NOT free the PGresult since we are keeping pointers into it */
7757         destroyPQExpBuffer(query);
7758
7759         *items = comments;
7760         return ntups;
7761 }
7762
7763 /*
7764  * dumpDumpableObject
7765  *
7766  * This routine and its subsidiaries are responsible for creating
7767  * ArchiveEntries (TOC objects) for each object to be dumped.
7768  */
7769 static void
7770 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7771 {
7772         switch (dobj->objType)
7773         {
7774                 case DO_NAMESPACE:
7775                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7776                         break;
7777                 case DO_EXTENSION:
7778                         dumpExtension(fout, (ExtensionInfo *) dobj);
7779                         break;
7780                 case DO_TYPE:
7781                         dumpType(fout, (TypeInfo *) dobj);
7782                         break;
7783                 case DO_SHELL_TYPE:
7784                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7785                         break;
7786                 case DO_FUNC:
7787                         dumpFunc(fout, (FuncInfo *) dobj);
7788                         break;
7789                 case DO_AGG:
7790                         dumpAgg(fout, (AggInfo *) dobj);
7791                         break;
7792                 case DO_OPERATOR:
7793                         dumpOpr(fout, (OprInfo *) dobj);
7794                         break;
7795                 case DO_OPCLASS:
7796                         dumpOpclass(fout, (OpclassInfo *) dobj);
7797                         break;
7798                 case DO_OPFAMILY:
7799                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7800                         break;
7801                 case DO_COLLATION:
7802                         dumpCollation(fout, (CollInfo *) dobj);
7803                         break;
7804                 case DO_CONVERSION:
7805                         dumpConversion(fout, (ConvInfo *) dobj);
7806                         break;
7807                 case DO_TABLE:
7808                         dumpTable(fout, (TableInfo *) dobj);
7809                         break;
7810                 case DO_ATTRDEF:
7811                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7812                         break;
7813                 case DO_INDEX:
7814                         dumpIndex(fout, (IndxInfo *) dobj);
7815                         break;
7816                 case DO_REFRESH_MATVIEW:
7817                         refreshMatViewData(fout, (TableDataInfo *) dobj);
7818                         break;
7819                 case DO_RULE:
7820                         dumpRule(fout, (RuleInfo *) dobj);
7821                         break;
7822                 case DO_TRIGGER:
7823                         dumpTrigger(fout, (TriggerInfo *) dobj);
7824                         break;
7825                 case DO_EVENT_TRIGGER:
7826                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7827                         break;
7828                 case DO_CONSTRAINT:
7829                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7830                         break;
7831                 case DO_FK_CONSTRAINT:
7832                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7833                         break;
7834                 case DO_PROCLANG:
7835                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7836                         break;
7837                 case DO_CAST:
7838                         dumpCast(fout, (CastInfo *) dobj);
7839                         break;
7840                 case DO_TABLE_DATA:
7841                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
7842                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
7843                         else
7844                                 dumpTableData(fout, (TableDataInfo *) dobj);
7845                         break;
7846                 case DO_DUMMY_TYPE:
7847                         /* table rowtypes and array types are never dumped separately */
7848                         break;
7849                 case DO_TSPARSER:
7850                         dumpTSParser(fout, (TSParserInfo *) dobj);
7851                         break;
7852                 case DO_TSDICT:
7853                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7854                         break;
7855                 case DO_TSTEMPLATE:
7856                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7857                         break;
7858                 case DO_TSCONFIG:
7859                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7860                         break;
7861                 case DO_FDW:
7862                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7863                         break;
7864                 case DO_FOREIGN_SERVER:
7865                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7866                         break;
7867                 case DO_DEFAULT_ACL:
7868                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7869                         break;
7870                 case DO_BLOB:
7871                         dumpBlob(fout, (BlobInfo *) dobj);
7872                         break;
7873                 case DO_BLOB_DATA:
7874                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7875                                                  dobj->name, NULL, NULL, "",
7876                                                  false, "BLOBS", SECTION_DATA,
7877                                                  "", "", NULL,
7878                                                  NULL, 0,
7879                                                  dumpBlobs, NULL);
7880                         break;
7881                 case DO_PRE_DATA_BOUNDARY:
7882                 case DO_POST_DATA_BOUNDARY:
7883                         /* never dumped, nothing to do */
7884                         break;
7885         }
7886 }
7887
7888 /*
7889  * dumpNamespace
7890  *        writes out to fout the queries to recreate a user-defined namespace
7891  */
7892 static void
7893 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7894 {
7895         PQExpBuffer q;
7896         PQExpBuffer delq;
7897         PQExpBuffer labelq;
7898         char       *qnspname;
7899
7900         /* Skip if not to be dumped */
7901         if (!nspinfo->dobj.dump || dataOnly)
7902                 return;
7903
7904         /* don't dump dummy namespace from pre-7.3 source */
7905         if (strlen(nspinfo->dobj.name) == 0)
7906                 return;
7907
7908         q = createPQExpBuffer();
7909         delq = createPQExpBuffer();
7910         labelq = createPQExpBuffer();
7911
7912         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7913
7914         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7915
7916         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7917
7918         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7919
7920         if (binary_upgrade)
7921                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7922
7923         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7924                                  nspinfo->dobj.name,
7925                                  NULL, NULL,
7926                                  nspinfo->rolname,
7927                                  false, "SCHEMA", SECTION_PRE_DATA,
7928                                  q->data, delq->data, NULL,
7929                                  NULL, 0,
7930                                  NULL, NULL);
7931
7932         /* Dump Schema Comments and Security Labels */
7933         dumpComment(fout, labelq->data,
7934                                 NULL, nspinfo->rolname,
7935                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7936         dumpSecLabel(fout, labelq->data,
7937                                  NULL, nspinfo->rolname,
7938                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7939
7940         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7941                         qnspname, NULL, nspinfo->dobj.name, NULL,
7942                         nspinfo->rolname, nspinfo->nspacl);
7943
7944         free(qnspname);
7945
7946         destroyPQExpBuffer(q);
7947         destroyPQExpBuffer(delq);
7948         destroyPQExpBuffer(labelq);
7949 }
7950
7951 /*
7952  * dumpExtension
7953  *        writes out to fout the queries to recreate an extension
7954  */
7955 static void
7956 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7957 {
7958         PQExpBuffer q;
7959         PQExpBuffer delq;
7960         PQExpBuffer labelq;
7961         char       *qextname;
7962
7963         /* Skip if not to be dumped */
7964         if (!extinfo->dobj.dump || dataOnly)
7965                 return;
7966
7967         q = createPQExpBuffer();
7968         delq = createPQExpBuffer();
7969         labelq = createPQExpBuffer();
7970
7971         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7972
7973         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7974
7975         if (!binary_upgrade)
7976         {
7977                 /*
7978                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7979                  * problem if the extension already exists in the target database;
7980                  * this is essential for installed-by-default extensions such as
7981                  * plpgsql.
7982                  *
7983                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7984                  * built-in extensions based on their OIDs; see
7985                  * selectDumpableExtension.
7986                  */
7987                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7988                                                   qextname, fmtId(extinfo->namespace));
7989         }
7990         else
7991         {
7992                 int                     i;
7993                 int                     n;
7994
7995                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7996
7997                 /*
7998                  * We unconditionally create the extension, so we must drop it if it
7999                  * exists.  This could happen if the user deleted 'plpgsql' and then
8000                  * readded it, causing its oid to be greater than FirstNormalObjectId.
8001                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
8002                  * and recreating extensions like 'plpgsql'.
8003                  */
8004                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
8005
8006                 appendPQExpBufferStr(q,
8007                                                          "SELECT binary_upgrade.create_empty_extension(");
8008                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
8009                 appendPQExpBufferStr(q, ", ");
8010                 appendStringLiteralAH(q, extinfo->namespace, fout);
8011                 appendPQExpBufferStr(q, ", ");
8012                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
8013                 appendStringLiteralAH(q, extinfo->extversion, fout);
8014                 appendPQExpBufferStr(q, ", ");
8015
8016                 /*
8017                  * Note that we're pushing extconfig (an OID array) back into
8018                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
8019                  * preserved in binary upgrade.
8020                  */
8021                 if (strlen(extinfo->extconfig) > 2)
8022                         appendStringLiteralAH(q, extinfo->extconfig, fout);
8023                 else
8024                         appendPQExpBufferStr(q, "NULL");
8025                 appendPQExpBufferStr(q, ", ");
8026                 if (strlen(extinfo->extcondition) > 2)
8027                         appendStringLiteralAH(q, extinfo->extcondition, fout);
8028                 else
8029                         appendPQExpBufferStr(q, "NULL");
8030                 appendPQExpBufferStr(q, ", ");
8031                 appendPQExpBufferStr(q, "ARRAY[");
8032                 n = 0;
8033                 for (i = 0; i < extinfo->dobj.nDeps; i++)
8034                 {
8035                         DumpableObject *extobj;
8036
8037                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
8038                         if (extobj && extobj->objType == DO_EXTENSION)
8039                         {
8040                                 if (n++ > 0)
8041                                         appendPQExpBufferChar(q, ',');
8042                                 appendStringLiteralAH(q, extobj->name, fout);
8043                         }
8044                 }
8045                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
8046                 appendPQExpBufferStr(q, ");\n");
8047         }
8048
8049         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
8050
8051         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
8052                                  extinfo->dobj.name,
8053                                  NULL, NULL,
8054                                  "",
8055                                  false, "EXTENSION", SECTION_PRE_DATA,
8056                                  q->data, delq->data, NULL,
8057                                  NULL, 0,
8058                                  NULL, NULL);
8059
8060         /* Dump Extension Comments and Security Labels */
8061         dumpComment(fout, labelq->data,
8062                                 NULL, "",
8063                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8064         dumpSecLabel(fout, labelq->data,
8065                                  NULL, "",
8066                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8067
8068         free(qextname);
8069
8070         destroyPQExpBuffer(q);
8071         destroyPQExpBuffer(delq);
8072         destroyPQExpBuffer(labelq);
8073 }
8074
8075 /*
8076  * dumpType
8077  *        writes out to fout the queries to recreate a user-defined type
8078  */
8079 static void
8080 dumpType(Archive *fout, TypeInfo *tyinfo)
8081 {
8082         /* Skip if not to be dumped */
8083         if (!tyinfo->dobj.dump || dataOnly)
8084                 return;
8085
8086         /* Dump out in proper style */
8087         if (tyinfo->typtype == TYPTYPE_BASE)
8088                 dumpBaseType(fout, tyinfo);
8089         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
8090                 dumpDomain(fout, tyinfo);
8091         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
8092                 dumpCompositeType(fout, tyinfo);
8093         else if (tyinfo->typtype == TYPTYPE_ENUM)
8094                 dumpEnumType(fout, tyinfo);
8095         else if (tyinfo->typtype == TYPTYPE_RANGE)
8096                 dumpRangeType(fout, tyinfo);
8097         else
8098                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
8099                                   tyinfo->dobj.name);
8100 }
8101
8102 /*
8103  * dumpEnumType
8104  *        writes out to fout the queries to recreate a user-defined enum type
8105  */
8106 static void
8107 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
8108 {
8109         PQExpBuffer q = createPQExpBuffer();
8110         PQExpBuffer delq = createPQExpBuffer();
8111         PQExpBuffer labelq = createPQExpBuffer();
8112         PQExpBuffer query = createPQExpBuffer();
8113         PGresult   *res;
8114         int                     num,
8115                                 i;
8116         Oid                     enum_oid;
8117         char       *qtypname;
8118         char       *label;
8119
8120         /* Set proper schema search path */
8121         selectSourceSchema(fout, "pg_catalog");
8122
8123         if (fout->remoteVersion >= 90100)
8124                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8125                                                   "FROM pg_catalog.pg_enum "
8126                                                   "WHERE enumtypid = '%u'"
8127                                                   "ORDER BY enumsortorder",
8128                                                   tyinfo->dobj.catId.oid);
8129         else
8130                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8131                                                   "FROM pg_catalog.pg_enum "
8132                                                   "WHERE enumtypid = '%u'"
8133                                                   "ORDER BY oid",
8134                                                   tyinfo->dobj.catId.oid);
8135
8136         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8137
8138         num = PQntuples(res);
8139
8140         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8141
8142         /*
8143          * DROP must be fully qualified in case same name appears in pg_catalog.
8144          * CASCADE shouldn't be required here as for normal types since the I/O
8145          * functions are generic and do not get dropped.
8146          */
8147         appendPQExpBuffer(delq, "DROP TYPE %s.",
8148                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8149         appendPQExpBuffer(delq, "%s;\n",
8150                                           qtypname);
8151
8152         if (binary_upgrade)
8153                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8154                                                                                                  tyinfo->dobj.catId.oid);
8155
8156         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8157                                           qtypname);
8158
8159         if (!binary_upgrade)
8160         {
8161                 /* Labels with server-assigned oids */
8162                 for (i = 0; i < num; i++)
8163                 {
8164                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8165                         if (i > 0)
8166                                 appendPQExpBufferChar(q, ',');
8167                         appendPQExpBufferStr(q, "\n    ");
8168                         appendStringLiteralAH(q, label, fout);
8169                 }
8170         }
8171
8172         appendPQExpBufferStr(q, "\n);\n");
8173
8174         if (binary_upgrade)
8175         {
8176                 /* Labels with dump-assigned (preserved) oids */
8177                 for (i = 0; i < num; i++)
8178                 {
8179                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8180                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8181
8182                         if (i == 0)
8183                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8184                         appendPQExpBuffer(q,
8185                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8186                                                           enum_oid);
8187                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8188                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8189                         appendPQExpBuffer(q, "%s ADD VALUE ",
8190                                                           qtypname);
8191                         appendStringLiteralAH(q, label, fout);
8192                         appendPQExpBufferStr(q, ";\n\n");
8193                 }
8194         }
8195
8196         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8197
8198         if (binary_upgrade)
8199                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8200
8201         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8202                                  tyinfo->dobj.name,
8203                                  tyinfo->dobj.namespace->dobj.name,
8204                                  NULL,
8205                                  tyinfo->rolname, false,
8206                                  "TYPE", SECTION_PRE_DATA,
8207                                  q->data, delq->data, NULL,
8208                                  NULL, 0,
8209                                  NULL, NULL);
8210
8211         /* Dump Type Comments and Security Labels */
8212         dumpComment(fout, labelq->data,
8213                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8214                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8215         dumpSecLabel(fout, labelq->data,
8216                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8217                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8218
8219         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8220                         qtypname, NULL, tyinfo->dobj.name,
8221                         tyinfo->dobj.namespace->dobj.name,
8222                         tyinfo->rolname, tyinfo->typacl);
8223
8224         PQclear(res);
8225         destroyPQExpBuffer(q);
8226         destroyPQExpBuffer(delq);
8227         destroyPQExpBuffer(labelq);
8228         destroyPQExpBuffer(query);
8229 }
8230
8231 /*
8232  * dumpRangeType
8233  *        writes out to fout the queries to recreate a user-defined range type
8234  */
8235 static void
8236 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
8237 {
8238         PQExpBuffer q = createPQExpBuffer();
8239         PQExpBuffer delq = createPQExpBuffer();
8240         PQExpBuffer labelq = createPQExpBuffer();
8241         PQExpBuffer query = createPQExpBuffer();
8242         PGresult   *res;
8243         Oid                     collationOid;
8244         char       *qtypname;
8245         char       *procname;
8246
8247         /*
8248          * select appropriate schema to ensure names in CREATE are properly
8249          * qualified
8250          */
8251         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8252
8253         appendPQExpBuffer(query,
8254                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8255                                           "opc.opcname AS opcname, "
8256                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8257                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8258                                           "opc.opcdefault, "
8259                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8260                                           "     ELSE rngcollation END AS collation, "
8261                                           "rngcanonical, rngsubdiff "
8262                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8263                                           "     pg_catalog.pg_opclass opc "
8264                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8265                                           "rngtypid = '%u'",
8266                                           tyinfo->dobj.catId.oid);
8267
8268         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8269
8270         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8271
8272         /*
8273          * DROP must be fully qualified in case same name appears in pg_catalog.
8274          * CASCADE shouldn't be required here as for normal types since the I/O
8275          * functions are generic and do not get dropped.
8276          */
8277         appendPQExpBuffer(delq, "DROP TYPE %s.",
8278                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8279         appendPQExpBuffer(delq, "%s;\n",
8280                                           qtypname);
8281
8282         if (binary_upgrade)
8283                 binary_upgrade_set_type_oids_by_type_oid(fout,
8284                                                                                                  q, tyinfo->dobj.catId.oid);
8285
8286         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8287                                           qtypname);
8288
8289         appendPQExpBuffer(q, "\n    subtype = %s",
8290                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8291
8292         /* print subtype_opclass only if not default for subtype */
8293         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8294         {
8295                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8296                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8297
8298                 /* always schema-qualify, don't try to be smart */
8299                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8300                                                   fmtId(nspname));
8301                 appendPQExpBufferStr(q, fmtId(opcname));
8302         }
8303
8304         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8305         if (OidIsValid(collationOid))
8306         {
8307                 CollInfo   *coll = findCollationByOid(collationOid);
8308
8309                 if (coll)
8310                 {
8311                         /* always schema-qualify, don't try to be smart */
8312                         appendPQExpBuffer(q, ",\n    collation = %s.",
8313                                                           fmtId(coll->dobj.namespace->dobj.name));
8314                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
8315                 }
8316         }
8317
8318         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8319         if (strcmp(procname, "-") != 0)
8320                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8321
8322         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8323         if (strcmp(procname, "-") != 0)
8324                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8325
8326         appendPQExpBufferStr(q, "\n);\n");
8327
8328         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8329
8330         if (binary_upgrade)
8331                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8332
8333         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8334                                  tyinfo->dobj.name,
8335                                  tyinfo->dobj.namespace->dobj.name,
8336                                  NULL,
8337                                  tyinfo->rolname, false,
8338                                  "TYPE", SECTION_PRE_DATA,
8339                                  q->data, delq->data, NULL,
8340                                  NULL, 0,
8341                                  NULL, NULL);
8342
8343         /* Dump Type Comments and Security Labels */
8344         dumpComment(fout, labelq->data,
8345                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8346                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8347         dumpSecLabel(fout, labelq->data,
8348                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8349                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8350
8351         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8352                         qtypname, NULL, tyinfo->dobj.name,
8353                         tyinfo->dobj.namespace->dobj.name,
8354                         tyinfo->rolname, tyinfo->typacl);
8355
8356         PQclear(res);
8357         destroyPQExpBuffer(q);
8358         destroyPQExpBuffer(delq);
8359         destroyPQExpBuffer(labelq);
8360         destroyPQExpBuffer(query);
8361 }
8362
8363 /*
8364  * dumpBaseType
8365  *        writes out to fout the queries to recreate a user-defined base type
8366  */
8367 static void
8368 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
8369 {
8370         PQExpBuffer q = createPQExpBuffer();
8371         PQExpBuffer delq = createPQExpBuffer();
8372         PQExpBuffer labelq = createPQExpBuffer();
8373         PQExpBuffer query = createPQExpBuffer();
8374         PGresult   *res;
8375         char       *qtypname;
8376         char       *typlen;
8377         char       *typinput;
8378         char       *typoutput;
8379         char       *typreceive;
8380         char       *typsend;
8381         char       *typmodin;
8382         char       *typmodout;
8383         char       *typanalyze;
8384         Oid                     typreceiveoid;
8385         Oid                     typsendoid;
8386         Oid                     typmodinoid;
8387         Oid                     typmodoutoid;
8388         Oid                     typanalyzeoid;
8389         char       *typcategory;
8390         char       *typispreferred;
8391         char       *typdelim;
8392         char       *typbyval;
8393         char       *typalign;
8394         char       *typstorage;
8395         char       *typcollatable;
8396         char       *typdefault;
8397         bool            typdefault_is_literal = false;
8398
8399         /* Set proper schema search path so regproc references list correctly */
8400         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8401
8402         /* Fetch type-specific details */
8403         if (fout->remoteVersion >= 90100)
8404         {
8405                 appendPQExpBuffer(query, "SELECT typlen, "
8406                                                   "typinput, typoutput, typreceive, typsend, "
8407                                                   "typmodin, typmodout, typanalyze, "
8408                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8409                                                   "typsend::pg_catalog.oid AS typsendoid, "
8410                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8411                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8412                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8413                                                   "typcategory, typispreferred, "
8414                                                   "typdelim, typbyval, typalign, typstorage, "
8415                                                   "(typcollation <> 0) AS typcollatable, "
8416                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8417                                                   "FROM pg_catalog.pg_type "
8418                                                   "WHERE oid = '%u'::pg_catalog.oid",
8419                                                   tyinfo->dobj.catId.oid);
8420         }
8421         else if (fout->remoteVersion >= 80400)
8422         {
8423                 appendPQExpBuffer(query, "SELECT typlen, "
8424                                                   "typinput, typoutput, typreceive, typsend, "
8425                                                   "typmodin, typmodout, typanalyze, "
8426                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8427                                                   "typsend::pg_catalog.oid AS typsendoid, "
8428                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8429                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8430                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8431                                                   "typcategory, typispreferred, "
8432                                                   "typdelim, typbyval, typalign, typstorage, "
8433                                                   "false AS typcollatable, "
8434                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8435                                                   "FROM pg_catalog.pg_type "
8436                                                   "WHERE oid = '%u'::pg_catalog.oid",
8437                                                   tyinfo->dobj.catId.oid);
8438         }
8439         else if (fout->remoteVersion >= 80300)
8440         {
8441                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8442                 appendPQExpBuffer(query, "SELECT typlen, "
8443                                                   "typinput, typoutput, typreceive, typsend, "
8444                                                   "typmodin, typmodout, typanalyze, "
8445                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8446                                                   "typsend::pg_catalog.oid AS typsendoid, "
8447                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8448                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8449                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8450                                                   "'U' AS typcategory, false AS typispreferred, "
8451                                                   "typdelim, typbyval, typalign, typstorage, "
8452                                                   "false AS typcollatable, "
8453                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8454                                                   "FROM pg_catalog.pg_type "
8455                                                   "WHERE oid = '%u'::pg_catalog.oid",
8456                                                   tyinfo->dobj.catId.oid);
8457         }
8458         else if (fout->remoteVersion >= 80000)
8459         {
8460                 appendPQExpBuffer(query, "SELECT typlen, "
8461                                                   "typinput, typoutput, typreceive, typsend, "
8462                                                   "'-' AS typmodin, '-' AS typmodout, "
8463                                                   "typanalyze, "
8464                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8465                                                   "typsend::pg_catalog.oid AS typsendoid, "
8466                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8467                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8468                                                   "'U' AS typcategory, false AS typispreferred, "
8469                                                   "typdelim, typbyval, typalign, typstorage, "
8470                                                   "false AS typcollatable, "
8471                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8472                                                   "FROM pg_catalog.pg_type "
8473                                                   "WHERE oid = '%u'::pg_catalog.oid",
8474                                                   tyinfo->dobj.catId.oid);
8475         }
8476         else if (fout->remoteVersion >= 70400)
8477         {
8478                 appendPQExpBuffer(query, "SELECT typlen, "
8479                                                   "typinput, typoutput, typreceive, typsend, "
8480                                                   "'-' AS typmodin, '-' AS typmodout, "
8481                                                   "'-' AS typanalyze, "
8482                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8483                                                   "typsend::pg_catalog.oid AS typsendoid, "
8484                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8485                                                   "0 AS typanalyzeoid, "
8486                                                   "'U' AS typcategory, false AS typispreferred, "
8487                                                   "typdelim, typbyval, typalign, typstorage, "
8488                                                   "false AS typcollatable, "
8489                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8490                                                   "FROM pg_catalog.pg_type "
8491                                                   "WHERE oid = '%u'::pg_catalog.oid",
8492                                                   tyinfo->dobj.catId.oid);
8493         }
8494         else if (fout->remoteVersion >= 70300)
8495         {
8496                 appendPQExpBuffer(query, "SELECT typlen, "
8497                                                   "typinput, typoutput, "
8498                                                   "'-' AS typreceive, '-' AS typsend, "
8499                                                   "'-' AS typmodin, '-' AS typmodout, "
8500                                                   "'-' AS typanalyze, "
8501                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8502                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8503                                                   "0 AS typanalyzeoid, "
8504                                                   "'U' AS typcategory, false AS typispreferred, "
8505                                                   "typdelim, typbyval, typalign, typstorage, "
8506                                                   "false AS typcollatable, "
8507                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8508                                                   "FROM pg_catalog.pg_type "
8509                                                   "WHERE oid = '%u'::pg_catalog.oid",
8510                                                   tyinfo->dobj.catId.oid);
8511         }
8512         else if (fout->remoteVersion >= 70200)
8513         {
8514                 /*
8515                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8516                  * ignore them because they are not right.
8517                  */
8518                 appendPQExpBuffer(query, "SELECT typlen, "
8519                                                   "typinput, typoutput, "
8520                                                   "'-' AS typreceive, '-' AS typsend, "
8521                                                   "'-' AS typmodin, '-' AS typmodout, "
8522                                                   "'-' AS typanalyze, "
8523                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8524                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8525                                                   "0 AS typanalyzeoid, "
8526                                                   "'U' AS typcategory, false AS typispreferred, "
8527                                                   "typdelim, typbyval, typalign, typstorage, "
8528                                                   "false AS typcollatable, "
8529                                                   "NULL AS typdefaultbin, typdefault "
8530                                                   "FROM pg_type "
8531                                                   "WHERE oid = '%u'::oid",
8532                                                   tyinfo->dobj.catId.oid);
8533         }
8534         else if (fout->remoteVersion >= 70100)
8535         {
8536                 /*
8537                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8538                  * representation.
8539                  */
8540                 appendPQExpBuffer(query, "SELECT typlen, "
8541                                                   "typinput, typoutput, "
8542                                                   "'-' AS typreceive, '-' AS typsend, "
8543                                                   "'-' AS typmodin, '-' AS typmodout, "
8544                                                   "'-' AS typanalyze, "
8545                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8546                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8547                                                   "0 AS typanalyzeoid, "
8548                                                   "'U' AS typcategory, false AS typispreferred, "
8549                                                   "typdelim, typbyval, typalign, typstorage, "
8550                                                   "false AS typcollatable, "
8551                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8552                                                   "FROM pg_type "
8553                                                   "WHERE oid = '%u'::oid",
8554                                                   tyinfo->dobj.catId.oid);
8555         }
8556         else
8557         {
8558                 appendPQExpBuffer(query, "SELECT typlen, "
8559                                                   "typinput, typoutput, "
8560                                                   "'-' AS typreceive, '-' AS typsend, "
8561                                                   "'-' AS typmodin, '-' AS typmodout, "
8562                                                   "'-' AS typanalyze, "
8563                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8564                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8565                                                   "0 AS typanalyzeoid, "
8566                                                   "'U' AS typcategory, false AS typispreferred, "
8567                                                   "typdelim, typbyval, typalign, "
8568                                                   "'p'::char AS typstorage, "
8569                                                   "false AS typcollatable, "
8570                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8571                                                   "FROM pg_type "
8572                                                   "WHERE oid = '%u'::oid",
8573                                                   tyinfo->dobj.catId.oid);
8574         }
8575
8576         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8577
8578         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8579         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8580         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8581         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8582         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8583         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8584         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8585         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8586         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8587         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8588         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8589         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8590         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8591         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8592         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8593         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8594         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8595         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8596         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8597         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8598         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8599                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8600         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8601         {
8602                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8603                 typdefault_is_literal = true;   /* it needs quotes */
8604         }
8605         else
8606                 typdefault = NULL;
8607
8608         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8609
8610         /*
8611          * DROP must be fully qualified in case same name appears in pg_catalog.
8612          * The reason we include CASCADE is that the circular dependency between
8613          * the type and its I/O functions makes it impossible to drop the type any
8614          * other way.
8615          */
8616         appendPQExpBuffer(delq, "DROP TYPE %s.",
8617                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8618         appendPQExpBuffer(delq, "%s CASCADE;\n",
8619                                           qtypname);
8620
8621         /* We might already have a shell type, but setting pg_type_oid is harmless */
8622         if (binary_upgrade)
8623                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8624                                                                                                  tyinfo->dobj.catId.oid);
8625
8626         appendPQExpBuffer(q,
8627                                           "CREATE TYPE %s (\n"
8628                                           "    INTERNALLENGTH = %s",
8629                                           qtypname,
8630                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8631
8632         if (fout->remoteVersion >= 70300)
8633         {
8634                 /* regproc result is correctly quoted as of 7.3 */
8635                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8636                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8637                 if (OidIsValid(typreceiveoid))
8638                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8639                 if (OidIsValid(typsendoid))
8640                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8641                 if (OidIsValid(typmodinoid))
8642                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8643                 if (OidIsValid(typmodoutoid))
8644                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8645                 if (OidIsValid(typanalyzeoid))
8646                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8647         }
8648         else
8649         {
8650                 /* regproc delivers an unquoted name before 7.3 */
8651                 /* cannot combine these because fmtId uses static result area */
8652                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8653                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8654                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8655         }
8656
8657         if (strcmp(typcollatable, "t") == 0)
8658                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
8659
8660         if (typdefault != NULL)
8661         {
8662                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
8663                 if (typdefault_is_literal)
8664                         appendStringLiteralAH(q, typdefault, fout);
8665                 else
8666                         appendPQExpBufferStr(q, typdefault);
8667         }
8668
8669         if (OidIsValid(tyinfo->typelem))
8670         {
8671                 char       *elemType;
8672
8673                 /* reselect schema in case changed by function dump */
8674                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8675                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8676                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8677                 free(elemType);
8678         }
8679
8680         if (strcmp(typcategory, "U") != 0)
8681         {
8682                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
8683                 appendStringLiteralAH(q, typcategory, fout);
8684         }
8685
8686         if (strcmp(typispreferred, "t") == 0)
8687                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
8688
8689         if (typdelim && strcmp(typdelim, ",") != 0)
8690         {
8691                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
8692                 appendStringLiteralAH(q, typdelim, fout);
8693         }
8694
8695         if (strcmp(typalign, "c") == 0)
8696                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
8697         else if (strcmp(typalign, "s") == 0)
8698                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
8699         else if (strcmp(typalign, "i") == 0)
8700                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
8701         else if (strcmp(typalign, "d") == 0)
8702                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
8703
8704         if (strcmp(typstorage, "p") == 0)
8705                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
8706         else if (strcmp(typstorage, "e") == 0)
8707                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
8708         else if (strcmp(typstorage, "x") == 0)
8709                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
8710         else if (strcmp(typstorage, "m") == 0)
8711                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
8712
8713         if (strcmp(typbyval, "t") == 0)
8714                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
8715
8716         appendPQExpBufferStr(q, "\n);\n");
8717
8718         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8719
8720         if (binary_upgrade)
8721                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8722
8723         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8724                                  tyinfo->dobj.name,
8725                                  tyinfo->dobj.namespace->dobj.name,
8726                                  NULL,
8727                                  tyinfo->rolname, false,
8728                                  "TYPE", SECTION_PRE_DATA,
8729                                  q->data, delq->data, NULL,
8730                                  NULL, 0,
8731                                  NULL, NULL);
8732
8733         /* Dump Type Comments and Security Labels */
8734         dumpComment(fout, labelq->data,
8735                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8736                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8737         dumpSecLabel(fout, labelq->data,
8738                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8739                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8740
8741         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8742                         qtypname, NULL, tyinfo->dobj.name,
8743                         tyinfo->dobj.namespace->dobj.name,
8744                         tyinfo->rolname, tyinfo->typacl);
8745
8746         PQclear(res);
8747         destroyPQExpBuffer(q);
8748         destroyPQExpBuffer(delq);
8749         destroyPQExpBuffer(labelq);
8750         destroyPQExpBuffer(query);
8751 }
8752
8753 /*
8754  * dumpDomain
8755  *        writes out to fout the queries to recreate a user-defined domain
8756  */
8757 static void
8758 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8759 {
8760         PQExpBuffer q = createPQExpBuffer();
8761         PQExpBuffer delq = createPQExpBuffer();
8762         PQExpBuffer labelq = createPQExpBuffer();
8763         PQExpBuffer query = createPQExpBuffer();
8764         PGresult   *res;
8765         int                     i;
8766         char       *qtypname;
8767         char       *typnotnull;
8768         char       *typdefn;
8769         char       *typdefault;
8770         Oid                     typcollation;
8771         bool            typdefault_is_literal = false;
8772
8773         /* Set proper schema search path so type references list correctly */
8774         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8775
8776         /* Fetch domain specific details */
8777         if (fout->remoteVersion >= 90100)
8778         {
8779                 /* typcollation is new in 9.1 */
8780                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8781                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8782                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8783                                                   "t.typdefault, "
8784                                                   "CASE WHEN t.typcollation <> u.typcollation "
8785                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8786                                                   "FROM pg_catalog.pg_type t "
8787                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8788                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8789                                                   tyinfo->dobj.catId.oid);
8790         }
8791         else
8792         {
8793                 /* We assume here that remoteVersion must be at least 70300 */
8794                 appendPQExpBuffer(query, "SELECT typnotnull, "
8795                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8796                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8797                                                   "typdefault, 0 AS typcollation "
8798                                                   "FROM pg_catalog.pg_type "
8799                                                   "WHERE oid = '%u'::pg_catalog.oid",
8800                                                   tyinfo->dobj.catId.oid);
8801         }
8802
8803         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8804
8805         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8806         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8807         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8808                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8809         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8810         {
8811                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8812                 typdefault_is_literal = true;   /* it needs quotes */
8813         }
8814         else
8815                 typdefault = NULL;
8816         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8817
8818         if (binary_upgrade)
8819                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8820                                                                                                  tyinfo->dobj.catId.oid);
8821
8822         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8823
8824         appendPQExpBuffer(q,
8825                                           "CREATE DOMAIN %s AS %s",
8826                                           qtypname,
8827                                           typdefn);
8828
8829         /* Print collation only if different from base type's collation */
8830         if (OidIsValid(typcollation))
8831         {
8832                 CollInfo   *coll;
8833
8834                 coll = findCollationByOid(typcollation);
8835                 if (coll)
8836                 {
8837                         /* always schema-qualify, don't try to be smart */
8838                         appendPQExpBuffer(q, " COLLATE %s.",
8839                                                           fmtId(coll->dobj.namespace->dobj.name));
8840                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
8841                 }
8842         }
8843
8844         if (typnotnull[0] == 't')
8845                 appendPQExpBufferStr(q, " NOT NULL");
8846
8847         if (typdefault != NULL)
8848         {
8849                 appendPQExpBufferStr(q, " DEFAULT ");
8850                 if (typdefault_is_literal)
8851                         appendStringLiteralAH(q, typdefault, fout);
8852                 else
8853                         appendPQExpBufferStr(q, typdefault);
8854         }
8855
8856         PQclear(res);
8857
8858         /*
8859          * Add any CHECK constraints for the domain
8860          */
8861         for (i = 0; i < tyinfo->nDomChecks; i++)
8862         {
8863                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8864
8865                 if (!domcheck->separate)
8866                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8867                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8868         }
8869
8870         appendPQExpBufferStr(q, ";\n");
8871
8872         /*
8873          * DROP must be fully qualified in case same name appears in pg_catalog
8874          */
8875         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8876                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8877         appendPQExpBuffer(delq, "%s;\n",
8878                                           qtypname);
8879
8880         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
8881
8882         if (binary_upgrade)
8883                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8884
8885         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8886                                  tyinfo->dobj.name,
8887                                  tyinfo->dobj.namespace->dobj.name,
8888                                  NULL,
8889                                  tyinfo->rolname, false,
8890                                  "DOMAIN", SECTION_PRE_DATA,
8891                                  q->data, delq->data, NULL,
8892                                  NULL, 0,
8893                                  NULL, NULL);
8894
8895         /* Dump Domain Comments and Security Labels */
8896         dumpComment(fout, labelq->data,
8897                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8898                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8899         dumpSecLabel(fout, labelq->data,
8900                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8901                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8902
8903         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8904                         qtypname, NULL, tyinfo->dobj.name,
8905                         tyinfo->dobj.namespace->dobj.name,
8906                         tyinfo->rolname, tyinfo->typacl);
8907
8908         destroyPQExpBuffer(q);
8909         destroyPQExpBuffer(delq);
8910         destroyPQExpBuffer(labelq);
8911         destroyPQExpBuffer(query);
8912 }
8913
8914 /*
8915  * dumpCompositeType
8916  *        writes out to fout the queries to recreate a user-defined stand-alone
8917  *        composite type
8918  */
8919 static void
8920 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8921 {
8922         PQExpBuffer q = createPQExpBuffer();
8923         PQExpBuffer dropped = createPQExpBuffer();
8924         PQExpBuffer delq = createPQExpBuffer();
8925         PQExpBuffer labelq = createPQExpBuffer();
8926         PQExpBuffer query = createPQExpBuffer();
8927         PGresult   *res;
8928         char       *qtypname;
8929         int                     ntups;
8930         int                     i_attname;
8931         int                     i_atttypdefn;
8932         int                     i_attlen;
8933         int                     i_attalign;
8934         int                     i_attisdropped;
8935         int                     i_attcollation;
8936         int                     i_typrelid;
8937         int                     i;
8938         int                     actual_atts;
8939
8940         /* Set proper schema search path so type references list correctly */
8941         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8942
8943         /* Fetch type specific details */
8944         if (fout->remoteVersion >= 90100)
8945         {
8946                 /*
8947                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8948                  * clauses for attributes whose collation is different from their
8949                  * type's default, we use a CASE here to suppress uninteresting
8950                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8951                  * collation does not matter for those.
8952                  */
8953                 appendPQExpBuffer(query, "SELECT a.attname, "
8954                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8955                                                   "a.attlen, a.attalign, a.attisdropped, "
8956                                                   "CASE WHEN a.attcollation <> at.typcollation "
8957                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8958                                                   "ct.typrelid "
8959                                                   "FROM pg_catalog.pg_type ct "
8960                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8961                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8962                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8963                                                   "ORDER BY a.attnum ",
8964                                                   tyinfo->dobj.catId.oid);
8965         }
8966         else
8967         {
8968                 /*
8969                  * We assume here that remoteVersion must be at least 70300.  Since
8970                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8971                  * always be false.
8972                  */
8973                 appendPQExpBuffer(query, "SELECT a.attname, "
8974                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8975                                                   "a.attlen, a.attalign, a.attisdropped, "
8976                                                   "0 AS attcollation, "
8977                                                   "ct.typrelid "
8978                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8979                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8980                                                   "AND a.attrelid = ct.typrelid "
8981                                                   "ORDER BY a.attnum ",
8982                                                   tyinfo->dobj.catId.oid);
8983         }
8984
8985         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8986
8987         ntups = PQntuples(res);
8988
8989         i_attname = PQfnumber(res, "attname");
8990         i_atttypdefn = PQfnumber(res, "atttypdefn");
8991         i_attlen = PQfnumber(res, "attlen");
8992         i_attalign = PQfnumber(res, "attalign");
8993         i_attisdropped = PQfnumber(res, "attisdropped");
8994         i_attcollation = PQfnumber(res, "attcollation");
8995         i_typrelid = PQfnumber(res, "typrelid");
8996
8997         if (binary_upgrade)
8998         {
8999                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
9000
9001                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9002                                                                                                  tyinfo->dobj.catId.oid);
9003                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
9004         }
9005
9006         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9007
9008         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
9009                                           qtypname);
9010
9011         actual_atts = 0;
9012         for (i = 0; i < ntups; i++)
9013         {
9014                 char       *attname;
9015                 char       *atttypdefn;
9016                 char       *attlen;
9017                 char       *attalign;
9018                 bool            attisdropped;
9019                 Oid                     attcollation;
9020
9021                 attname = PQgetvalue(res, i, i_attname);
9022                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
9023                 attlen = PQgetvalue(res, i, i_attlen);
9024                 attalign = PQgetvalue(res, i, i_attalign);
9025                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
9026                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
9027
9028                 if (attisdropped && !binary_upgrade)
9029                         continue;
9030
9031                 /* Format properly if not first attr */
9032                 if (actual_atts++ > 0)
9033                         appendPQExpBufferChar(q, ',');
9034                 appendPQExpBufferStr(q, "\n\t");
9035
9036                 if (!attisdropped)
9037                 {
9038                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
9039
9040                         /* Add collation if not default for the column type */
9041                         if (OidIsValid(attcollation))
9042                         {
9043                                 CollInfo   *coll;
9044
9045                                 coll = findCollationByOid(attcollation);
9046                                 if (coll)
9047                                 {
9048                                         /* always schema-qualify, don't try to be smart */
9049                                         appendPQExpBuffer(q, " COLLATE %s.",
9050                                                                           fmtId(coll->dobj.namespace->dobj.name));
9051                                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
9052                                 }
9053                         }
9054                 }
9055                 else
9056                 {
9057                         /*
9058                          * This is a dropped attribute and we're in binary_upgrade mode.
9059                          * Insert a placeholder for it in the CREATE TYPE command, and set
9060                          * length and alignment with direct UPDATE to the catalogs
9061                          * afterwards. See similar code in dumpTableSchema().
9062                          */
9063                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
9064
9065                         /* stash separately for insertion after the CREATE TYPE */
9066                         appendPQExpBufferStr(dropped,
9067                                           "\n-- For binary upgrade, recreate dropped column.\n");
9068                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
9069                                                           "SET attlen = %s, "
9070                                                           "attalign = '%s', attbyval = false\n"
9071                                                           "WHERE attname = ", attlen, attalign);
9072                         appendStringLiteralAH(dropped, attname, fout);
9073                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
9074                         appendStringLiteralAH(dropped, qtypname, fout);
9075                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
9076
9077                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
9078                                                           qtypname);
9079                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
9080                                                           fmtId(attname));
9081                 }
9082         }
9083         appendPQExpBufferStr(q, "\n);\n");
9084         appendPQExpBufferStr(q, dropped->data);
9085
9086         /*
9087          * DROP must be fully qualified in case same name appears in pg_catalog
9088          */
9089         appendPQExpBuffer(delq, "DROP TYPE %s.",
9090                                           fmtId(tyinfo->dobj.namespace->dobj.name));
9091         appendPQExpBuffer(delq, "%s;\n",
9092                                           qtypname);
9093
9094         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
9095
9096         if (binary_upgrade)
9097                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9098
9099         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9100                                  tyinfo->dobj.name,
9101                                  tyinfo->dobj.namespace->dobj.name,
9102                                  NULL,
9103                                  tyinfo->rolname, false,
9104                                  "TYPE", SECTION_PRE_DATA,
9105                                  q->data, delq->data, NULL,
9106                                  NULL, 0,
9107                                  NULL, NULL);
9108
9109
9110         /* Dump Type Comments and Security Labels */
9111         dumpComment(fout, labelq->data,
9112                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9113                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9114         dumpSecLabel(fout, labelq->data,
9115                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9116                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9117
9118         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9119                         qtypname, NULL, tyinfo->dobj.name,
9120                         tyinfo->dobj.namespace->dobj.name,
9121                         tyinfo->rolname, tyinfo->typacl);
9122
9123         PQclear(res);
9124         destroyPQExpBuffer(q);
9125         destroyPQExpBuffer(dropped);
9126         destroyPQExpBuffer(delq);
9127         destroyPQExpBuffer(labelq);
9128         destroyPQExpBuffer(query);
9129
9130         /* Dump any per-column comments */
9131         dumpCompositeTypeColComments(fout, tyinfo);
9132 }
9133
9134 /*
9135  * dumpCompositeTypeColComments
9136  *        writes out to fout the queries to recreate comments on the columns of
9137  *        a user-defined stand-alone composite type
9138  */
9139 static void
9140 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9141 {
9142         CommentItem *comments;
9143         int                     ncomments;
9144         PGresult   *res;
9145         PQExpBuffer query;
9146         PQExpBuffer target;
9147         Oid                     pgClassOid;
9148         int                     i;
9149         int                     ntups;
9150         int                     i_attname;
9151         int                     i_attnum;
9152
9153         query = createPQExpBuffer();
9154
9155         /* We assume here that remoteVersion must be at least 70300 */
9156         appendPQExpBuffer(query,
9157                                           "SELECT c.tableoid, a.attname, a.attnum "
9158                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9159                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9160                                           "  AND NOT a.attisdropped "
9161                                           "ORDER BY a.attnum ",
9162                                           tyinfo->typrelid);
9163
9164         /* Fetch column attnames */
9165         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9166
9167         ntups = PQntuples(res);
9168         if (ntups < 1)
9169         {
9170                 PQclear(res);
9171                 destroyPQExpBuffer(query);
9172                 return;
9173         }
9174
9175         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9176
9177         /* Search for comments associated with type's pg_class OID */
9178         ncomments = findComments(fout,
9179                                                          pgClassOid,
9180                                                          tyinfo->typrelid,
9181                                                          &comments);
9182
9183         /* If no comments exist, we're done */
9184         if (ncomments <= 0)
9185         {
9186                 PQclear(res);
9187                 destroyPQExpBuffer(query);
9188                 return;
9189         }
9190
9191         /* Build COMMENT ON statements */
9192         target = createPQExpBuffer();
9193
9194         i_attnum = PQfnumber(res, "attnum");
9195         i_attname = PQfnumber(res, "attname");
9196         while (ncomments > 0)
9197         {
9198                 const char *attname;
9199
9200                 attname = NULL;
9201                 for (i = 0; i < ntups; i++)
9202                 {
9203                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9204                         {
9205                                 attname = PQgetvalue(res, i, i_attname);
9206                                 break;
9207                         }
9208                 }
9209                 if (attname)                    /* just in case we don't find it */
9210                 {
9211                         const char *descr = comments->descr;
9212
9213                         resetPQExpBuffer(target);
9214                         appendPQExpBuffer(target, "COLUMN %s.",
9215                                                           fmtId(tyinfo->dobj.name));
9216                         appendPQExpBufferStr(target, fmtId(attname));
9217
9218                         resetPQExpBuffer(query);
9219                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9220                         appendStringLiteralAH(query, descr, fout);
9221                         appendPQExpBufferStr(query, ";\n");
9222
9223                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9224                                                  target->data,
9225                                                  tyinfo->dobj.namespace->dobj.name,
9226                                                  NULL, tyinfo->rolname,
9227                                                  false, "COMMENT", SECTION_NONE,
9228                                                  query->data, "", NULL,
9229                                                  &(tyinfo->dobj.dumpId), 1,
9230                                                  NULL, NULL);
9231                 }
9232
9233                 comments++;
9234                 ncomments--;
9235         }
9236
9237         PQclear(res);
9238         destroyPQExpBuffer(query);
9239         destroyPQExpBuffer(target);
9240 }
9241
9242 /*
9243  * dumpShellType
9244  *        writes out to fout the queries to create a shell type
9245  *
9246  * We dump a shell definition in advance of the I/O functions for the type.
9247  */
9248 static void
9249 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
9250 {
9251         PQExpBuffer q;
9252
9253         /* Skip if not to be dumped */
9254         if (!stinfo->dobj.dump || dataOnly)
9255                 return;
9256
9257         q = createPQExpBuffer();
9258
9259         /*
9260          * Note the lack of a DROP command for the shell type; any required DROP
9261          * is driven off the base type entry, instead.  This interacts with
9262          * _printTocEntry()'s use of the presence of a DROP command to decide
9263          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9264          * the shell type's owner immediately on creation; that should happen only
9265          * after it's filled in, otherwise the backend complains.
9266          */
9267
9268         if (binary_upgrade)
9269                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9270                                                                                    stinfo->baseType->dobj.catId.oid);
9271
9272         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9273                                           fmtId(stinfo->dobj.name));
9274
9275         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9276                                  stinfo->dobj.name,
9277                                  stinfo->dobj.namespace->dobj.name,
9278                                  NULL,
9279                                  stinfo->baseType->rolname, false,
9280                                  "SHELL TYPE", SECTION_PRE_DATA,
9281                                  q->data, "", NULL,
9282                                  NULL, 0,
9283                                  NULL, NULL);
9284
9285         destroyPQExpBuffer(q);
9286 }
9287
9288 /*
9289  * Determine whether we want to dump definitions for procedural languages.
9290  * Since the languages themselves don't have schemas, we can't rely on
9291  * the normal schema-based selection mechanism.  We choose to dump them
9292  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9293  * the dump flag of the PL's call handler function, but in 8.1 this will
9294  * probably always be false since call handlers are created in pg_catalog.)
9295  *
9296  * For some backwards compatibility with the older behavior, we forcibly
9297  * dump a PL if its handler function (and validator if any) are in a
9298  * dumpable namespace.  That case is not checked here.
9299  *
9300  * Also, if the PL belongs to an extension, we do not use this heuristic.
9301  * That case isn't checked here either.
9302  */
9303 static bool
9304 shouldDumpProcLangs(void)
9305 {
9306         if (!include_everything)
9307                 return false;
9308         /* And they're schema not data */
9309         if (dataOnly)
9310                 return false;
9311         return true;
9312 }
9313
9314 /*
9315  * dumpProcLang
9316  *                writes out to fout the queries to recreate a user-defined
9317  *                procedural language
9318  */
9319 static void
9320 dumpProcLang(Archive *fout, ProcLangInfo *plang)
9321 {
9322         PQExpBuffer defqry;
9323         PQExpBuffer delqry;
9324         PQExpBuffer labelq;
9325         bool            useParams;
9326         char       *qlanname;
9327         char       *lanschema;
9328         FuncInfo   *funcInfo;
9329         FuncInfo   *inlineInfo = NULL;
9330         FuncInfo   *validatorInfo = NULL;
9331
9332         /* Skip if not to be dumped */
9333         if (!plang->dobj.dump || dataOnly)
9334                 return;
9335
9336         /*
9337          * Try to find the support function(s).  It is not an error if we don't
9338          * find them --- if the functions are in the pg_catalog schema, as is
9339          * standard in 8.1 and up, then we won't have loaded them. (In this case
9340          * we will emit a parameterless CREATE LANGUAGE command, which will
9341          * require PL template knowledge in the backend to reload.)
9342          */
9343
9344         funcInfo = findFuncByOid(plang->lanplcallfoid);
9345         if (funcInfo != NULL && !funcInfo->dobj.dump)
9346                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9347
9348         if (OidIsValid(plang->laninline))
9349         {
9350                 inlineInfo = findFuncByOid(plang->laninline);
9351                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9352                         inlineInfo = NULL;
9353         }
9354
9355         if (OidIsValid(plang->lanvalidator))
9356         {
9357                 validatorInfo = findFuncByOid(plang->lanvalidator);
9358                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9359                         validatorInfo = NULL;
9360         }
9361
9362         /*
9363          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9364          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9365          * dump it.
9366          *
9367          * However, for a language that belongs to an extension, we must not use
9368          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9369          * told to (via dobj.dump).  Generally the support functions will belong
9370          * to the same extension and so have the same dump flags ... if they
9371          * don't, this might not work terribly nicely.
9372          */
9373         useParams = (funcInfo != NULL &&
9374                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9375                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9376
9377         if (!plang->dobj.ext_member)
9378         {
9379                 if (!useParams && !shouldDumpProcLangs())
9380                         return;
9381         }
9382
9383         defqry = createPQExpBuffer();
9384         delqry = createPQExpBuffer();
9385         labelq = createPQExpBuffer();
9386
9387         qlanname = pg_strdup(fmtId(plang->dobj.name));
9388
9389         /*
9390          * If dumping a HANDLER clause, treat the language as being in the handler
9391          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9392          * it doesn't really have a schema.
9393          */
9394         if (useParams)
9395                 lanschema = funcInfo->dobj.namespace->dobj.name;
9396         else
9397                 lanschema = NULL;
9398
9399         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9400                                           qlanname);
9401
9402         if (useParams)
9403         {
9404                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9405                                                   plang->lanpltrusted ? "TRUSTED " : "",
9406                                                   qlanname);
9407                 appendPQExpBuffer(defqry, " HANDLER %s",
9408                                                   fmtId(funcInfo->dobj.name));
9409                 if (OidIsValid(plang->laninline))
9410                 {
9411                         appendPQExpBufferStr(defqry, " INLINE ");
9412                         /* Cope with possibility that inline is in different schema */
9413                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9414                                 appendPQExpBuffer(defqry, "%s.",
9415                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9416                         appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name));
9417                 }
9418                 if (OidIsValid(plang->lanvalidator))
9419                 {
9420                         appendPQExpBufferStr(defqry, " VALIDATOR ");
9421                         /* Cope with possibility that validator is in different schema */
9422                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9423                                 appendPQExpBuffer(defqry, "%s.",
9424                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9425                         appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name));
9426                 }
9427         }
9428         else
9429         {
9430                 /*
9431                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9432                  * command will not fail if the language is preinstalled in the target
9433                  * database.  We restrict the use of REPLACE to this case so as to
9434                  * eliminate the risk of replacing a language with incompatible
9435                  * parameter settings: this command will only succeed at all if there
9436                  * is a pg_pltemplate entry, and if there is one, the existing entry
9437                  * must match it too.
9438                  */
9439                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9440                                                   qlanname);
9441         }
9442         appendPQExpBufferStr(defqry, ";\n");
9443
9444         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9445
9446         if (binary_upgrade)
9447                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9448
9449         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9450                                  plang->dobj.name,
9451                                  lanschema, NULL, plang->lanowner,
9452                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9453                                  defqry->data, delqry->data, NULL,
9454                                  NULL, 0,
9455                                  NULL, NULL);
9456
9457         /* Dump Proc Lang Comments and Security Labels */
9458         dumpComment(fout, labelq->data,
9459                                 NULL, "",
9460                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9461         dumpSecLabel(fout, labelq->data,
9462                                  NULL, "",
9463                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9464
9465         if (plang->lanpltrusted)
9466                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9467                                 qlanname, NULL, plang->dobj.name,
9468                                 lanschema,
9469                                 plang->lanowner, plang->lanacl);
9470
9471         free(qlanname);
9472
9473         destroyPQExpBuffer(defqry);
9474         destroyPQExpBuffer(delqry);
9475         destroyPQExpBuffer(labelq);
9476 }
9477
9478 /*
9479  * format_function_arguments: generate function name and argument list
9480  *
9481  * This is used when we can rely on pg_get_function_arguments to format
9482  * the argument list.  Note, however, that pg_get_function_arguments
9483  * does not special-case zero-argument aggregates.
9484  */
9485 static char *
9486 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
9487 {
9488         PQExpBufferData fn;
9489
9490         initPQExpBuffer(&fn);
9491         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
9492         if (is_agg && finfo->nargs == 0)
9493                 appendPQExpBufferStr(&fn, "(*)");
9494         else
9495                 appendPQExpBuffer(&fn, "(%s)", funcargs);
9496         return fn.data;
9497 }
9498
9499 /*
9500  * format_function_arguments_old: generate function name and argument list
9501  *
9502  * The argument type names are qualified if needed.  The function name
9503  * is never qualified.
9504  *
9505  * This is used only with pre-8.4 servers, so we aren't expecting to see
9506  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9507  *
9508  * Any or all of allargtypes, argmodes, argnames may be NULL.
9509  */
9510 static char *
9511 format_function_arguments_old(Archive *fout,
9512                                                           FuncInfo *finfo, int nallargs,
9513                                                           char **allargtypes,
9514                                                           char **argmodes,
9515                                                           char **argnames)
9516 {
9517         PQExpBufferData fn;
9518         int                     j;
9519
9520         initPQExpBuffer(&fn);
9521         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9522         for (j = 0; j < nallargs; j++)
9523         {
9524                 Oid                     typid;
9525                 char       *typname;
9526                 const char *argmode;
9527                 const char *argname;
9528
9529                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9530                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9531
9532                 if (argmodes)
9533                 {
9534                         switch (argmodes[j][0])
9535                         {
9536                                 case PROARGMODE_IN:
9537                                         argmode = "";
9538                                         break;
9539                                 case PROARGMODE_OUT:
9540                                         argmode = "OUT ";
9541                                         break;
9542                                 case PROARGMODE_INOUT:
9543                                         argmode = "INOUT ";
9544                                         break;
9545                                 default:
9546                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9547                                         argmode = "";
9548                                         break;
9549                         }
9550                 }
9551                 else
9552                         argmode = "";
9553
9554                 argname = argnames ? argnames[j] : (char *) NULL;
9555                 if (argname && argname[0] == '\0')
9556                         argname = NULL;
9557
9558                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9559                                                   (j > 0) ? ", " : "",
9560                                                   argmode,
9561                                                   argname ? fmtId(argname) : "",
9562                                                   argname ? " " : "",
9563                                                   typname);
9564                 free(typname);
9565         }
9566         appendPQExpBufferChar(&fn, ')');
9567         return fn.data;
9568 }
9569
9570 /*
9571  * format_function_signature: generate function name and argument list
9572  *
9573  * This is like format_function_arguments_old except that only a minimal
9574  * list of input argument types is generated; this is sufficient to
9575  * reference the function, but not to define it.
9576  *
9577  * If honor_quotes is false then the function name is never quoted.
9578  * This is appropriate for use in TOC tags, but not in SQL commands.
9579  */
9580 static char *
9581 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9582 {
9583         PQExpBufferData fn;
9584         int                     j;
9585
9586         initPQExpBuffer(&fn);
9587         if (honor_quotes)
9588                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9589         else
9590                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9591         for (j = 0; j < finfo->nargs; j++)
9592         {
9593                 char       *typname;
9594
9595                 if (j > 0)
9596                         appendPQExpBufferStr(&fn, ", ");
9597
9598                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9599                                                                            zeroAsOpaque);
9600                 appendPQExpBufferStr(&fn, typname);
9601                 free(typname);
9602         }
9603         appendPQExpBufferChar(&fn, ')');
9604         return fn.data;
9605 }
9606
9607
9608 /*
9609  * dumpFunc:
9610  *        dump out one function
9611  */
9612 static void
9613 dumpFunc(Archive *fout, FuncInfo *finfo)
9614 {
9615         PQExpBuffer query;
9616         PQExpBuffer q;
9617         PQExpBuffer delqry;
9618         PQExpBuffer labelq;
9619         PQExpBuffer asPart;
9620         PGresult   *res;
9621         char       *funcsig;            /* identity signature */
9622         char       *funcfullsig = NULL;         /* full signature */
9623         char       *funcsig_tag;
9624         char       *proretset;
9625         char       *prosrc;
9626         char       *probin;
9627         char       *funcargs;
9628         char       *funciargs;
9629         char       *funcresult;
9630         char       *proallargtypes;
9631         char       *proargmodes;
9632         char       *proargnames;
9633         char       *proiswindow;
9634         char       *provolatile;
9635         char       *proisstrict;
9636         char       *prosecdef;
9637         char       *proleakproof;
9638         char       *proconfig;
9639         char       *procost;
9640         char       *prorows;
9641         char       *lanname;
9642         char       *rettypename;
9643         int                     nallargs;
9644         char      **allargtypes = NULL;
9645         char      **argmodes = NULL;
9646         char      **argnames = NULL;
9647         char      **configitems = NULL;
9648         int                     nconfigitems = 0;
9649         int                     i;
9650
9651         /* Skip if not to be dumped */
9652         if (!finfo->dobj.dump || dataOnly)
9653                 return;
9654
9655         query = createPQExpBuffer();
9656         q = createPQExpBuffer();
9657         delqry = createPQExpBuffer();
9658         labelq = createPQExpBuffer();
9659         asPart = createPQExpBuffer();
9660
9661         /* Set proper schema search path so type references list correctly */
9662         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9663
9664         /* Fetch function-specific details */
9665         if (fout->remoteVersion >= 90200)
9666         {
9667                 /*
9668                  * proleakproof was added at v9.2
9669                  */
9670                 appendPQExpBuffer(query,
9671                                                   "SELECT proretset, prosrc, probin, "
9672                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9673                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9674                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9675                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9676                                                   "proleakproof, proconfig, procost, prorows, "
9677                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9678                                                   "FROM pg_catalog.pg_proc "
9679                                                   "WHERE oid = '%u'::pg_catalog.oid",
9680                                                   finfo->dobj.catId.oid);
9681         }
9682         else if (fout->remoteVersion >= 80400)
9683         {
9684                 /*
9685                  * In 8.4 and up we rely on pg_get_function_arguments and
9686                  * pg_get_function_result instead of examining proallargtypes etc.
9687                  */
9688                 appendPQExpBuffer(query,
9689                                                   "SELECT proretset, prosrc, probin, "
9690                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9691                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9692                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9693                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9694                                                   "false AS proleakproof, "
9695                                                   " proconfig, procost, prorows, "
9696                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9697                                                   "FROM pg_catalog.pg_proc "
9698                                                   "WHERE oid = '%u'::pg_catalog.oid",
9699                                                   finfo->dobj.catId.oid);
9700         }
9701         else if (fout->remoteVersion >= 80300)
9702         {
9703                 appendPQExpBuffer(query,
9704                                                   "SELECT proretset, prosrc, probin, "
9705                                                   "proallargtypes, proargmodes, proargnames, "
9706                                                   "false AS proiswindow, "
9707                                                   "provolatile, proisstrict, prosecdef, "
9708                                                   "false AS proleakproof, "
9709                                                   "proconfig, procost, prorows, "
9710                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9711                                                   "FROM pg_catalog.pg_proc "
9712                                                   "WHERE oid = '%u'::pg_catalog.oid",
9713                                                   finfo->dobj.catId.oid);
9714         }
9715         else if (fout->remoteVersion >= 80100)
9716         {
9717                 appendPQExpBuffer(query,
9718                                                   "SELECT proretset, prosrc, probin, "
9719                                                   "proallargtypes, proargmodes, proargnames, "
9720                                                   "false AS proiswindow, "
9721                                                   "provolatile, proisstrict, prosecdef, "
9722                                                   "false AS proleakproof, "
9723                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9724                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9725                                                   "FROM pg_catalog.pg_proc "
9726                                                   "WHERE oid = '%u'::pg_catalog.oid",
9727                                                   finfo->dobj.catId.oid);
9728         }
9729         else if (fout->remoteVersion >= 80000)
9730         {
9731                 appendPQExpBuffer(query,
9732                                                   "SELECT proretset, prosrc, probin, "
9733                                                   "null AS proallargtypes, "
9734                                                   "null AS proargmodes, "
9735                                                   "proargnames, "
9736                                                   "false AS proiswindow, "
9737                                                   "provolatile, proisstrict, prosecdef, "
9738                                                   "false AS proleakproof, "
9739                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9740                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9741                                                   "FROM pg_catalog.pg_proc "
9742                                                   "WHERE oid = '%u'::pg_catalog.oid",
9743                                                   finfo->dobj.catId.oid);
9744         }
9745         else if (fout->remoteVersion >= 70300)
9746         {
9747                 appendPQExpBuffer(query,
9748                                                   "SELECT proretset, prosrc, probin, "
9749                                                   "null AS proallargtypes, "
9750                                                   "null AS proargmodes, "
9751                                                   "null AS proargnames, "
9752                                                   "false AS proiswindow, "
9753                                                   "provolatile, proisstrict, prosecdef, "
9754                                                   "false AS proleakproof, "
9755                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9756                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9757                                                   "FROM pg_catalog.pg_proc "
9758                                                   "WHERE oid = '%u'::pg_catalog.oid",
9759                                                   finfo->dobj.catId.oid);
9760         }
9761         else if (fout->remoteVersion >= 70100)
9762         {
9763                 appendPQExpBuffer(query,
9764                                                   "SELECT proretset, prosrc, probin, "
9765                                                   "null AS proallargtypes, "
9766                                                   "null AS proargmodes, "
9767                                                   "null AS proargnames, "
9768                                                   "false AS proiswindow, "
9769                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9770                                                   "proisstrict, "
9771                                                   "false AS prosecdef, "
9772                                                   "false AS proleakproof, "
9773                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9774                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9775                                                   "FROM pg_proc "
9776                                                   "WHERE oid = '%u'::oid",
9777                                                   finfo->dobj.catId.oid);
9778         }
9779         else
9780         {
9781                 appendPQExpBuffer(query,
9782                                                   "SELECT proretset, prosrc, probin, "
9783                                                   "null AS proallargtypes, "
9784                                                   "null AS proargmodes, "
9785                                                   "null AS proargnames, "
9786                                                   "false AS proiswindow, "
9787                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9788                                                   "false AS proisstrict, "
9789                                                   "false AS prosecdef, "
9790                                                   "false AS proleakproof, "
9791                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9792                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9793                                                   "FROM pg_proc "
9794                                                   "WHERE oid = '%u'::oid",
9795                                                   finfo->dobj.catId.oid);
9796         }
9797
9798         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9799
9800         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9801         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9802         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9803         if (fout->remoteVersion >= 80400)
9804         {
9805                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9806                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9807                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9808                 proallargtypes = proargmodes = proargnames = NULL;
9809         }
9810         else
9811         {
9812                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9813                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9814                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9815                 funcargs = funciargs = funcresult = NULL;
9816         }
9817         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9818         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9819         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9820         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9821         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9822         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9823         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9824         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9825         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9826
9827         /*
9828          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9829          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9830          * versions would set it to "-".  There are no known cases in which prosrc
9831          * is unused, so the tests below for "-" are probably useless.
9832          */
9833         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9834         {
9835                 appendPQExpBufferStr(asPart, "AS ");
9836                 appendStringLiteralAH(asPart, probin, fout);
9837                 if (strcmp(prosrc, "-") != 0)
9838                 {
9839                         appendPQExpBufferStr(asPart, ", ");
9840
9841                         /*
9842                          * where we have bin, use dollar quoting if allowed and src
9843                          * contains quote or backslash; else use regular quoting.
9844                          */
9845                         if (disable_dollar_quoting ||
9846                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9847                                 appendStringLiteralAH(asPart, prosrc, fout);
9848                         else
9849                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9850                 }
9851         }
9852         else
9853         {
9854                 if (strcmp(prosrc, "-") != 0)
9855                 {
9856                         appendPQExpBufferStr(asPart, "AS ");
9857                         /* with no bin, dollar quote src unconditionally if allowed */
9858                         if (disable_dollar_quoting)
9859                                 appendStringLiteralAH(asPart, prosrc, fout);
9860                         else
9861                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9862                 }
9863         }
9864
9865         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9866
9867         if (proallargtypes && *proallargtypes)
9868         {
9869                 int                     nitems = 0;
9870
9871                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9872                         nitems < finfo->nargs)
9873                 {
9874                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9875                         if (allargtypes)
9876                                 free(allargtypes);
9877                         allargtypes = NULL;
9878                 }
9879                 else
9880                         nallargs = nitems;
9881         }
9882
9883         if (proargmodes && *proargmodes)
9884         {
9885                 int                     nitems = 0;
9886
9887                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9888                         nitems != nallargs)
9889                 {
9890                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9891                         if (argmodes)
9892                                 free(argmodes);
9893                         argmodes = NULL;
9894                 }
9895         }
9896
9897         if (proargnames && *proargnames)
9898         {
9899                 int                     nitems = 0;
9900
9901                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9902                         nitems != nallargs)
9903                 {
9904                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9905                         if (argnames)
9906                                 free(argnames);
9907                         argnames = NULL;
9908                 }
9909         }
9910
9911         if (proconfig && *proconfig)
9912         {
9913                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9914                 {
9915                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9916                         if (configitems)
9917                                 free(configitems);
9918                         configitems = NULL;
9919                         nconfigitems = 0;
9920                 }
9921         }
9922
9923         if (funcargs)
9924         {
9925                 /* 8.4 or later; we rely on server-side code for most of the work */
9926                 funcfullsig = format_function_arguments(finfo, funcargs, false);
9927                 funcsig = format_function_arguments(finfo, funciargs, false);
9928         }
9929         else
9930                 /* pre-8.4, do it ourselves */
9931                 funcsig = format_function_arguments_old(fout,
9932                                                                                                 finfo, nallargs, allargtypes,
9933                                                                                                 argmodes, argnames);
9934
9935         funcsig_tag = format_function_signature(fout, finfo, false);
9936
9937         /*
9938          * DROP must be fully qualified in case same name appears in pg_catalog
9939          */
9940         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9941                                           fmtId(finfo->dobj.namespace->dobj.name),
9942                                           funcsig);
9943
9944         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig :
9945                                           funcsig);
9946         if (funcresult)
9947                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9948         else
9949         {
9950                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9951                                                                                    zeroAsOpaque);
9952                 appendPQExpBuffer(q, "RETURNS %s%s",
9953                                                   (proretset[0] == 't') ? "SETOF " : "",
9954                                                   rettypename);
9955                 free(rettypename);
9956         }
9957
9958         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9959
9960         if (proiswindow[0] == 't')
9961                 appendPQExpBufferStr(q, " WINDOW");
9962
9963         if (provolatile[0] != PROVOLATILE_VOLATILE)
9964         {
9965                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9966                         appendPQExpBufferStr(q, " IMMUTABLE");
9967                 else if (provolatile[0] == PROVOLATILE_STABLE)
9968                         appendPQExpBufferStr(q, " STABLE");
9969                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9970                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9971                                                   finfo->dobj.name);
9972         }
9973
9974         if (proisstrict[0] == 't')
9975                 appendPQExpBufferStr(q, " STRICT");
9976
9977         if (prosecdef[0] == 't')
9978                 appendPQExpBufferStr(q, " SECURITY DEFINER");
9979
9980         if (proleakproof[0] == 't')
9981                 appendPQExpBufferStr(q, " LEAKPROOF");
9982
9983         /*
9984          * COST and ROWS are emitted only if present and not default, so as not to
9985          * break backwards-compatibility of the dump without need.  Keep this code
9986          * in sync with the defaults in functioncmds.c.
9987          */
9988         if (strcmp(procost, "0") != 0)
9989         {
9990                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9991                 {
9992                         /* default cost is 1 */
9993                         if (strcmp(procost, "1") != 0)
9994                                 appendPQExpBuffer(q, " COST %s", procost);
9995                 }
9996                 else
9997                 {
9998                         /* default cost is 100 */
9999                         if (strcmp(procost, "100") != 0)
10000                                 appendPQExpBuffer(q, " COST %s", procost);
10001                 }
10002         }
10003         if (proretset[0] == 't' &&
10004                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
10005                 appendPQExpBuffer(q, " ROWS %s", prorows);
10006
10007         for (i = 0; i < nconfigitems; i++)
10008         {
10009                 /* we feel free to scribble on configitems[] here */
10010                 char       *configitem = configitems[i];
10011                 char       *pos;
10012
10013                 pos = strchr(configitem, '=');
10014                 if (pos == NULL)
10015                         continue;
10016                 *pos++ = '\0';
10017                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
10018
10019                 /*
10020                  * Some GUC variable names are 'LIST' type and hence must not be
10021                  * quoted.
10022                  */
10023                 if (pg_strcasecmp(configitem, "DateStyle") == 0
10024                         || pg_strcasecmp(configitem, "search_path") == 0)
10025                         appendPQExpBufferStr(q, pos);
10026                 else
10027                         appendStringLiteralAH(q, pos, fout);
10028         }
10029
10030         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
10031
10032         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
10033
10034         if (binary_upgrade)
10035                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
10036
10037         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
10038                                  funcsig_tag,
10039                                  finfo->dobj.namespace->dobj.name,
10040                                  NULL,
10041                                  finfo->rolname, false,
10042                                  "FUNCTION", SECTION_PRE_DATA,
10043                                  q->data, delqry->data, NULL,
10044                                  NULL, 0,
10045                                  NULL, NULL);
10046
10047         /* Dump Function Comments and Security Labels */
10048         dumpComment(fout, labelq->data,
10049                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
10050                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
10051         dumpSecLabel(fout, labelq->data,
10052                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
10053                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
10054
10055         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
10056                         funcsig, NULL, funcsig_tag,
10057                         finfo->dobj.namespace->dobj.name,
10058                         finfo->rolname, finfo->proacl);
10059
10060         PQclear(res);
10061
10062         destroyPQExpBuffer(query);
10063         destroyPQExpBuffer(q);
10064         destroyPQExpBuffer(delqry);
10065         destroyPQExpBuffer(labelq);
10066         destroyPQExpBuffer(asPart);
10067         free(funcsig);
10068         if (funcfullsig)
10069                 free(funcfullsig);
10070         free(funcsig_tag);
10071         if (allargtypes)
10072                 free(allargtypes);
10073         if (argmodes)
10074                 free(argmodes);
10075         if (argnames)
10076                 free(argnames);
10077         if (configitems)
10078                 free(configitems);
10079 }
10080
10081
10082 /*
10083  * Dump a user-defined cast
10084  */
10085 static void
10086 dumpCast(Archive *fout, CastInfo *cast)
10087 {
10088         PQExpBuffer defqry;
10089         PQExpBuffer delqry;
10090         PQExpBuffer labelq;
10091         FuncInfo   *funcInfo = NULL;
10092
10093         /* Skip if not to be dumped */
10094         if (!cast->dobj.dump || dataOnly)
10095                 return;
10096
10097         /* Cannot dump if we don't have the cast function's info */
10098         if (OidIsValid(cast->castfunc))
10099         {
10100                 funcInfo = findFuncByOid(cast->castfunc);
10101                 if (funcInfo == NULL)
10102                         return;
10103         }
10104
10105         /*
10106          * As per discussion we dump casts if one or more of the underlying
10107          * objects (the conversion function and the two data types) are not
10108          * builtin AND if all of the non-builtin objects are included in the dump.
10109          * Builtin meaning, the namespace name does not start with "pg_".
10110          *
10111          * However, for a cast that belongs to an extension, we must not use this
10112          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
10113          */
10114         if (!cast->dobj.ext_member)
10115         {
10116                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
10117                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
10118
10119                 if (sourceInfo == NULL || targetInfo == NULL)
10120                         return;
10121
10122                 /*
10123                  * Skip this cast if all objects are from pg_
10124                  */
10125                 if ((funcInfo == NULL ||
10126                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
10127                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10128                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10129                         return;
10130
10131                 /*
10132                  * Skip cast if function isn't from pg_ and is not to be dumped.
10133                  */
10134                 if (funcInfo &&
10135                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10136                         !funcInfo->dobj.dump)
10137                         return;
10138
10139                 /*
10140                  * Same for the source type
10141                  */
10142                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10143                         !sourceInfo->dobj.dump)
10144                         return;
10145
10146                 /*
10147                  * and the target type.
10148                  */
10149                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10150                         !targetInfo->dobj.dump)
10151                         return;
10152         }
10153
10154         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10155         selectSourceSchema(fout, "pg_catalog");
10156
10157         defqry = createPQExpBuffer();
10158         delqry = createPQExpBuffer();
10159         labelq = createPQExpBuffer();
10160
10161         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10162                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10163                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10164
10165         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10166                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10167                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10168
10169         switch (cast->castmethod)
10170         {
10171                 case COERCION_METHOD_BINARY:
10172                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
10173                         break;
10174                 case COERCION_METHOD_INOUT:
10175                         appendPQExpBufferStr(defqry, "WITH INOUT");
10176                         break;
10177                 case COERCION_METHOD_FUNCTION:
10178                         if (funcInfo)
10179                         {
10180                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10181
10182                                 /*
10183                                  * Always qualify the function name, in case it is not in
10184                                  * pg_catalog schema (format_function_signature won't qualify
10185                                  * it).
10186                                  */
10187                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10188                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10189                                 free(fsig);
10190                         }
10191                         else
10192                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10193                         break;
10194                 default:
10195                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10196         }
10197
10198         if (cast->castcontext == 'a')
10199                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
10200         else if (cast->castcontext == 'i')
10201                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
10202         appendPQExpBufferStr(defqry, ";\n");
10203
10204         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10205                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10206                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10207
10208         if (binary_upgrade)
10209                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10210
10211         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10212                                  labelq->data,
10213                                  "pg_catalog", NULL, "",
10214                                  false, "CAST", SECTION_PRE_DATA,
10215                                  defqry->data, delqry->data, NULL,
10216                                  NULL, 0,
10217                                  NULL, NULL);
10218
10219         /* Dump Cast Comments */
10220         dumpComment(fout, labelq->data,
10221                                 NULL, "",
10222                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10223
10224         destroyPQExpBuffer(defqry);
10225         destroyPQExpBuffer(delqry);
10226         destroyPQExpBuffer(labelq);
10227 }
10228
10229 /*
10230  * dumpOpr
10231  *        write out a single operator definition
10232  */
10233 static void
10234 dumpOpr(Archive *fout, OprInfo *oprinfo)
10235 {
10236         PQExpBuffer query;
10237         PQExpBuffer q;
10238         PQExpBuffer delq;
10239         PQExpBuffer labelq;
10240         PQExpBuffer oprid;
10241         PQExpBuffer details;
10242         const char *name;
10243         PGresult   *res;
10244         int                     i_oprkind;
10245         int                     i_oprcode;
10246         int                     i_oprleft;
10247         int                     i_oprright;
10248         int                     i_oprcom;
10249         int                     i_oprnegate;
10250         int                     i_oprrest;
10251         int                     i_oprjoin;
10252         int                     i_oprcanmerge;
10253         int                     i_oprcanhash;
10254         char       *oprkind;
10255         char       *oprcode;
10256         char       *oprleft;
10257         char       *oprright;
10258         char       *oprcom;
10259         char       *oprnegate;
10260         char       *oprrest;
10261         char       *oprjoin;
10262         char       *oprcanmerge;
10263         char       *oprcanhash;
10264         char       *oprregproc;
10265         char       *oprref;
10266
10267         /* Skip if not to be dumped */
10268         if (!oprinfo->dobj.dump || dataOnly)
10269                 return;
10270
10271         /*
10272          * some operators are invalid because they were the result of user
10273          * defining operators before commutators exist
10274          */
10275         if (!OidIsValid(oprinfo->oprcode))
10276                 return;
10277
10278         query = createPQExpBuffer();
10279         q = createPQExpBuffer();
10280         delq = createPQExpBuffer();
10281         labelq = createPQExpBuffer();
10282         oprid = createPQExpBuffer();
10283         details = createPQExpBuffer();
10284
10285         /* Make sure we are in proper schema so regoperator works correctly */
10286         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10287
10288         if (fout->remoteVersion >= 80300)
10289         {
10290                 appendPQExpBuffer(query, "SELECT oprkind, "
10291                                                   "oprcode::pg_catalog.regprocedure, "
10292                                                   "oprleft::pg_catalog.regtype, "
10293                                                   "oprright::pg_catalog.regtype, "
10294                                                   "oprcom::pg_catalog.regoperator, "
10295                                                   "oprnegate::pg_catalog.regoperator, "
10296                                                   "oprrest::pg_catalog.regprocedure, "
10297                                                   "oprjoin::pg_catalog.regprocedure, "
10298                                                   "oprcanmerge, oprcanhash "
10299                                                   "FROM pg_catalog.pg_operator "
10300                                                   "WHERE oid = '%u'::pg_catalog.oid",
10301                                                   oprinfo->dobj.catId.oid);
10302         }
10303         else if (fout->remoteVersion >= 70300)
10304         {
10305                 appendPQExpBuffer(query, "SELECT oprkind, "
10306                                                   "oprcode::pg_catalog.regprocedure, "
10307                                                   "oprleft::pg_catalog.regtype, "
10308                                                   "oprright::pg_catalog.regtype, "
10309                                                   "oprcom::pg_catalog.regoperator, "
10310                                                   "oprnegate::pg_catalog.regoperator, "
10311                                                   "oprrest::pg_catalog.regprocedure, "
10312                                                   "oprjoin::pg_catalog.regprocedure, "
10313                                                   "(oprlsortop != 0) AS oprcanmerge, "
10314                                                   "oprcanhash "
10315                                                   "FROM pg_catalog.pg_operator "
10316                                                   "WHERE oid = '%u'::pg_catalog.oid",
10317                                                   oprinfo->dobj.catId.oid);
10318         }
10319         else if (fout->remoteVersion >= 70100)
10320         {
10321                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10322                                                   "CASE WHEN oprleft = 0 THEN '-' "
10323                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10324                                                   "CASE WHEN oprright = 0 THEN '-' "
10325                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10326                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10327                                                   "(oprlsortop != 0) AS oprcanmerge, "
10328                                                   "oprcanhash "
10329                                                   "FROM pg_operator "
10330                                                   "WHERE oid = '%u'::oid",
10331                                                   oprinfo->dobj.catId.oid);
10332         }
10333         else
10334         {
10335                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10336                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10337                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10338                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10339                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10340                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10341                                                   "(oprlsortop != 0) AS oprcanmerge, "
10342                                                   "oprcanhash "
10343                                                   "FROM pg_operator "
10344                                                   "WHERE oid = '%u'::oid",
10345                                                   oprinfo->dobj.catId.oid);
10346         }
10347
10348         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10349
10350         i_oprkind = PQfnumber(res, "oprkind");
10351         i_oprcode = PQfnumber(res, "oprcode");
10352         i_oprleft = PQfnumber(res, "oprleft");
10353         i_oprright = PQfnumber(res, "oprright");
10354         i_oprcom = PQfnumber(res, "oprcom");
10355         i_oprnegate = PQfnumber(res, "oprnegate");
10356         i_oprrest = PQfnumber(res, "oprrest");
10357         i_oprjoin = PQfnumber(res, "oprjoin");
10358         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10359         i_oprcanhash = PQfnumber(res, "oprcanhash");
10360
10361         oprkind = PQgetvalue(res, 0, i_oprkind);
10362         oprcode = PQgetvalue(res, 0, i_oprcode);
10363         oprleft = PQgetvalue(res, 0, i_oprleft);
10364         oprright = PQgetvalue(res, 0, i_oprright);
10365         oprcom = PQgetvalue(res, 0, i_oprcom);
10366         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10367         oprrest = PQgetvalue(res, 0, i_oprrest);
10368         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10369         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10370         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10371
10372         oprregproc = convertRegProcReference(fout, oprcode);
10373         if (oprregproc)
10374         {
10375                 appendPQExpBuffer(details, "    PROCEDURE = %s", oprregproc);
10376                 free(oprregproc);
10377         }
10378
10379         appendPQExpBuffer(oprid, "%s (",
10380                                           oprinfo->dobj.name);
10381
10382         /*
10383          * right unary means there's a left arg and left unary means there's a
10384          * right arg
10385          */
10386         if (strcmp(oprkind, "r") == 0 ||
10387                 strcmp(oprkind, "b") == 0)
10388         {
10389                 if (fout->remoteVersion >= 70100)
10390                         name = oprleft;
10391                 else
10392                         name = fmtId(oprleft);
10393                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10394                 appendPQExpBufferStr(oprid, name);
10395         }
10396         else
10397                 appendPQExpBufferStr(oprid, "NONE");
10398
10399         if (strcmp(oprkind, "l") == 0 ||
10400                 strcmp(oprkind, "b") == 0)
10401         {
10402                 if (fout->remoteVersion >= 70100)
10403                         name = oprright;
10404                 else
10405                         name = fmtId(oprright);
10406                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10407                 appendPQExpBuffer(oprid, ", %s)", name);
10408         }
10409         else
10410                 appendPQExpBufferStr(oprid, ", NONE)");
10411
10412         oprref = convertOperatorReference(fout, oprcom);
10413         if (oprref)
10414         {
10415                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
10416                 free(oprref);
10417         }
10418
10419         oprref = convertOperatorReference(fout, oprnegate);
10420         if (oprref)
10421         {
10422                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
10423                 free(oprref);
10424         }
10425
10426         if (strcmp(oprcanmerge, "t") == 0)
10427                 appendPQExpBufferStr(details, ",\n    MERGES");
10428
10429         if (strcmp(oprcanhash, "t") == 0)
10430                 appendPQExpBufferStr(details, ",\n    HASHES");
10431
10432         oprregproc = convertRegProcReference(fout, oprrest);
10433         if (oprregproc)
10434         {
10435                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
10436                 free(oprregproc);
10437         }
10438
10439         oprregproc = convertRegProcReference(fout, oprjoin);
10440         if (oprregproc)
10441         {
10442                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
10443                 free(oprregproc);
10444         }
10445
10446         /*
10447          * DROP must be fully qualified in case same name appears in pg_catalog
10448          */
10449         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10450                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10451                                           oprid->data);
10452
10453         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10454                                           oprinfo->dobj.name, details->data);
10455
10456         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10457
10458         if (binary_upgrade)
10459                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10460
10461         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10462                                  oprinfo->dobj.name,
10463                                  oprinfo->dobj.namespace->dobj.name,
10464                                  NULL,
10465                                  oprinfo->rolname,
10466                                  false, "OPERATOR", SECTION_PRE_DATA,
10467                                  q->data, delq->data, NULL,
10468                                  NULL, 0,
10469                                  NULL, NULL);
10470
10471         /* Dump Operator Comments */
10472         dumpComment(fout, labelq->data,
10473                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10474                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10475
10476         PQclear(res);
10477
10478         destroyPQExpBuffer(query);
10479         destroyPQExpBuffer(q);
10480         destroyPQExpBuffer(delq);
10481         destroyPQExpBuffer(labelq);
10482         destroyPQExpBuffer(oprid);
10483         destroyPQExpBuffer(details);
10484 }
10485
10486 /*
10487  * Convert a function reference obtained from pg_operator
10488  *
10489  * Returns allocated string of what to print, or NULL if function references
10490  * is InvalidOid. Returned string is expected to be free'd by the caller.
10491  *
10492  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10493  * argument-types part.  In prior versions, the input is a REGPROC display.
10494  */
10495 static char *
10496 convertRegProcReference(Archive *fout, const char *proc)
10497 {
10498         /* In all cases "-" means a null reference */
10499         if (strcmp(proc, "-") == 0)
10500                 return NULL;
10501
10502         if (fout->remoteVersion >= 70300)
10503         {
10504                 char       *name;
10505                 char       *paren;
10506                 bool            inquote;
10507
10508                 name = pg_strdup(proc);
10509                 /* find non-double-quoted left paren */
10510                 inquote = false;
10511                 for (paren = name; *paren; paren++)
10512                 {
10513                         if (*paren == '(' && !inquote)
10514                         {
10515                                 *paren = '\0';
10516                                 break;
10517                         }
10518                         if (*paren == '"')
10519                                 inquote = !inquote;
10520                 }
10521                 return name;
10522         }
10523
10524         /* REGPROC before 7.3 does not quote its result */
10525         return pg_strdup(fmtId(proc));
10526 }
10527
10528 /*
10529  * Convert an operator cross-reference obtained from pg_operator
10530  *
10531  * Returns an allocated string of what to print, or NULL to print nothing.
10532  * Caller is responsible for free'ing result string.
10533  *
10534  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10535  * argument-types part, and add OPERATOR() decoration if the name is
10536  * schema-qualified.  In older versions, the input is just a numeric OID,
10537  * which we search our operator list for.
10538  */
10539 static char *
10540 convertOperatorReference(Archive *fout, const char *opr)
10541 {
10542         OprInfo    *oprInfo;
10543
10544         /* In all cases "0" means a null reference */
10545         if (strcmp(opr, "0") == 0)
10546                 return NULL;
10547
10548         if (fout->remoteVersion >= 70300)
10549         {
10550                 char       *name;
10551                 char       *oname;
10552                 char       *ptr;
10553                 bool            inquote;
10554                 bool            sawdot;
10555
10556                 name = pg_strdup(opr);
10557                 /* find non-double-quoted left paren, and check for non-quoted dot */
10558                 inquote = false;
10559                 sawdot = false;
10560                 for (ptr = name; *ptr; ptr++)
10561                 {
10562                         if (*ptr == '"')
10563                                 inquote = !inquote;
10564                         else if (*ptr == '.' && !inquote)
10565                                 sawdot = true;
10566                         else if (*ptr == '(' && !inquote)
10567                         {
10568                                 *ptr = '\0';
10569                                 break;
10570                         }
10571                 }
10572                 /* If not schema-qualified, don't need to add OPERATOR() */
10573                 if (!sawdot)
10574                         return name;
10575                 oname = psprintf("OPERATOR(%s)", name);
10576                 free(name);
10577                 return oname;
10578         }
10579
10580         oprInfo = findOprByOid(atooid(opr));
10581         if (oprInfo == NULL)
10582         {
10583                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10584                                   opr);
10585                 return NULL;
10586         }
10587         return pg_strdup(oprInfo->dobj.name);
10588 }
10589
10590 /*
10591  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10592  *
10593  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10594  * argument lists of these functions are predetermined.  Note that the
10595  * caller should ensure we are in the proper schema, because the results
10596  * are search path dependent!
10597  */
10598 static const char *
10599 convertTSFunction(Archive *fout, Oid funcOid)
10600 {
10601         char       *result;
10602         char            query[128];
10603         PGresult   *res;
10604
10605         snprintf(query, sizeof(query),
10606                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10607         res = ExecuteSqlQueryForSingleRow(fout, query);
10608
10609         result = pg_strdup(PQgetvalue(res, 0, 0));
10610
10611         PQclear(res);
10612
10613         return result;
10614 }
10615
10616
10617 /*
10618  * dumpOpclass
10619  *        write out a single operator class definition
10620  */
10621 static void
10622 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10623 {
10624         PQExpBuffer query;
10625         PQExpBuffer q;
10626         PQExpBuffer delq;
10627         PQExpBuffer labelq;
10628         PGresult   *res;
10629         int                     ntups;
10630         int                     i_opcintype;
10631         int                     i_opckeytype;
10632         int                     i_opcdefault;
10633         int                     i_opcfamily;
10634         int                     i_opcfamilyname;
10635         int                     i_opcfamilynsp;
10636         int                     i_amname;
10637         int                     i_amopstrategy;
10638         int                     i_amopreqcheck;
10639         int                     i_amopopr;
10640         int                     i_sortfamily;
10641         int                     i_sortfamilynsp;
10642         int                     i_amprocnum;
10643         int                     i_amproc;
10644         int                     i_amproclefttype;
10645         int                     i_amprocrighttype;
10646         char       *opcintype;
10647         char       *opckeytype;
10648         char       *opcdefault;
10649         char       *opcfamily;
10650         char       *opcfamilyname;
10651         char       *opcfamilynsp;
10652         char       *amname;
10653         char       *amopstrategy;
10654         char       *amopreqcheck;
10655         char       *amopopr;
10656         char       *sortfamily;
10657         char       *sortfamilynsp;
10658         char       *amprocnum;
10659         char       *amproc;
10660         char       *amproclefttype;
10661         char       *amprocrighttype;
10662         bool            needComma;
10663         int                     i;
10664
10665         /* Skip if not to be dumped */
10666         if (!opcinfo->dobj.dump || dataOnly)
10667                 return;
10668
10669         /*
10670          * XXX currently we do not implement dumping of operator classes from
10671          * pre-7.3 databases.  This could be done but it seems not worth the
10672          * trouble.
10673          */
10674         if (fout->remoteVersion < 70300)
10675                 return;
10676
10677         query = createPQExpBuffer();
10678         q = createPQExpBuffer();
10679         delq = createPQExpBuffer();
10680         labelq = createPQExpBuffer();
10681
10682         /* Make sure we are in proper schema so regoperator works correctly */
10683         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10684
10685         /* Get additional fields from the pg_opclass row */
10686         if (fout->remoteVersion >= 80300)
10687         {
10688                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10689                                                   "opckeytype::pg_catalog.regtype, "
10690                                                   "opcdefault, opcfamily, "
10691                                                   "opfname AS opcfamilyname, "
10692                                                   "nspname AS opcfamilynsp, "
10693                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10694                                                   "FROM pg_catalog.pg_opclass c "
10695                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10696                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10697                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10698                                                   opcinfo->dobj.catId.oid);
10699         }
10700         else
10701         {
10702                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10703                                                   "opckeytype::pg_catalog.regtype, "
10704                                                   "opcdefault, NULL AS opcfamily, "
10705                                                   "NULL AS opcfamilyname, "
10706                                                   "NULL AS opcfamilynsp, "
10707                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10708                                                   "FROM pg_catalog.pg_opclass "
10709                                                   "WHERE oid = '%u'::pg_catalog.oid",
10710                                                   opcinfo->dobj.catId.oid);
10711         }
10712
10713         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10714
10715         i_opcintype = PQfnumber(res, "opcintype");
10716         i_opckeytype = PQfnumber(res, "opckeytype");
10717         i_opcdefault = PQfnumber(res, "opcdefault");
10718         i_opcfamily = PQfnumber(res, "opcfamily");
10719         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10720         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10721         i_amname = PQfnumber(res, "amname");
10722
10723         opcintype = PQgetvalue(res, 0, i_opcintype);
10724         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10725         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10726         /* opcfamily will still be needed after we PQclear res */
10727         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10728         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10729         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10730         /* amname will still be needed after we PQclear res */
10731         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10732
10733         /*
10734          * DROP must be fully qualified in case same name appears in pg_catalog
10735          */
10736         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10737                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10738         appendPQExpBuffer(delq, ".%s",
10739                                           fmtId(opcinfo->dobj.name));
10740         appendPQExpBuffer(delq, " USING %s;\n",
10741                                           fmtId(amname));
10742
10743         /* Build the fixed portion of the CREATE command */
10744         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10745                                           fmtId(opcinfo->dobj.name));
10746         if (strcmp(opcdefault, "t") == 0)
10747                 appendPQExpBufferStr(q, "DEFAULT ");
10748         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10749                                           opcintype,
10750                                           fmtId(amname));
10751         if (strlen(opcfamilyname) > 0 &&
10752                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10753                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10754         {
10755                 appendPQExpBufferStr(q, " FAMILY ");
10756                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10757                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10758                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10759         }
10760         appendPQExpBufferStr(q, " AS\n    ");
10761
10762         needComma = false;
10763
10764         if (strcmp(opckeytype, "-") != 0)
10765         {
10766                 appendPQExpBuffer(q, "STORAGE %s",
10767                                                   opckeytype);
10768                 needComma = true;
10769         }
10770
10771         PQclear(res);
10772
10773         /*
10774          * Now fetch and print the OPERATOR entries (pg_amop rows).
10775          *
10776          * Print only those opfamily members that are tied to the opclass by
10777          * pg_depend entries.
10778          *
10779          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10780          * older server's opclass in which it is used.  This is to avoid
10781          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10782          * older server and then reload into that old version.  This can go away
10783          * once 8.3 is so old as to not be of interest to anyone.
10784          */
10785         resetPQExpBuffer(query);
10786
10787         if (fout->remoteVersion >= 90100)
10788         {
10789                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10790                                                   "amopopr::pg_catalog.regoperator, "
10791                                                   "opfname AS sortfamily, "
10792                                                   "nspname AS sortfamilynsp "
10793                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10794                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10795                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10796                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10797                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10798                                                   "AND refobjid = '%u'::pg_catalog.oid "
10799                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10800                                                   "ORDER BY amopstrategy",
10801                                                   opcinfo->dobj.catId.oid,
10802                                                   opcfamily);
10803         }
10804         else if (fout->remoteVersion >= 80400)
10805         {
10806                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10807                                                   "amopopr::pg_catalog.regoperator, "
10808                                                   "NULL AS sortfamily, "
10809                                                   "NULL AS sortfamilynsp "
10810                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10811                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10812                                                   "AND refobjid = '%u'::pg_catalog.oid "
10813                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10814                                                   "AND objid = ao.oid "
10815                                                   "ORDER BY amopstrategy",
10816                                                   opcinfo->dobj.catId.oid);
10817         }
10818         else if (fout->remoteVersion >= 80300)
10819         {
10820                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10821                                                   "amopopr::pg_catalog.regoperator, "
10822                                                   "NULL AS sortfamily, "
10823                                                   "NULL AS sortfamilynsp "
10824                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10825                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10826                                                   "AND refobjid = '%u'::pg_catalog.oid "
10827                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10828                                                   "AND objid = ao.oid "
10829                                                   "ORDER BY amopstrategy",
10830                                                   opcinfo->dobj.catId.oid);
10831         }
10832         else
10833         {
10834                 /*
10835                  * Here, we print all entries since there are no opfamilies and hence
10836                  * no loose operators to worry about.
10837                  */
10838                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10839                                                   "amopopr::pg_catalog.regoperator, "
10840                                                   "NULL AS sortfamily, "
10841                                                   "NULL AS sortfamilynsp "
10842                                                   "FROM pg_catalog.pg_amop "
10843                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10844                                                   "ORDER BY amopstrategy",
10845                                                   opcinfo->dobj.catId.oid);
10846         }
10847
10848         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10849
10850         ntups = PQntuples(res);
10851
10852         i_amopstrategy = PQfnumber(res, "amopstrategy");
10853         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10854         i_amopopr = PQfnumber(res, "amopopr");
10855         i_sortfamily = PQfnumber(res, "sortfamily");
10856         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10857
10858         for (i = 0; i < ntups; i++)
10859         {
10860                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10861                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10862                 amopopr = PQgetvalue(res, i, i_amopopr);
10863                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10864                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10865
10866                 if (needComma)
10867                         appendPQExpBufferStr(q, " ,\n    ");
10868
10869                 appendPQExpBuffer(q, "OPERATOR %s %s",
10870                                                   amopstrategy, amopopr);
10871
10872                 if (strlen(sortfamily) > 0)
10873                 {
10874                         appendPQExpBufferStr(q, " FOR ORDER BY ");
10875                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10876                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10877                         appendPQExpBufferStr(q, fmtId(sortfamily));
10878                 }
10879
10880                 if (strcmp(amopreqcheck, "t") == 0)
10881                         appendPQExpBufferStr(q, " RECHECK");
10882
10883                 needComma = true;
10884         }
10885
10886         PQclear(res);
10887
10888         /*
10889          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10890          *
10891          * Print only those opfamily members that are tied to the opclass by
10892          * pg_depend entries.
10893          *
10894          * We print the amproclefttype/amprocrighttype even though in most cases
10895          * the backend could deduce the right values, because of the corner case
10896          * of a btree sort support function for a cross-type comparison.  That's
10897          * only allowed in 9.2 and later, but for simplicity print them in all
10898          * versions that have the columns.
10899          */
10900         resetPQExpBuffer(query);
10901
10902         if (fout->remoteVersion >= 80300)
10903         {
10904                 appendPQExpBuffer(query, "SELECT amprocnum, "
10905                                                   "amproc::pg_catalog.regprocedure, "
10906                                                   "amproclefttype::pg_catalog.regtype, "
10907                                                   "amprocrighttype::pg_catalog.regtype "
10908                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10909                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10910                                                   "AND refobjid = '%u'::pg_catalog.oid "
10911                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10912                                                   "AND objid = ap.oid "
10913                                                   "ORDER BY amprocnum",
10914                                                   opcinfo->dobj.catId.oid);
10915         }
10916         else
10917         {
10918                 appendPQExpBuffer(query, "SELECT amprocnum, "
10919                                                   "amproc::pg_catalog.regprocedure, "
10920                                                   "'' AS amproclefttype, "
10921                                                   "'' AS amprocrighttype "
10922                                                   "FROM pg_catalog.pg_amproc "
10923                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10924                                                   "ORDER BY amprocnum",
10925                                                   opcinfo->dobj.catId.oid);
10926         }
10927
10928         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10929
10930         ntups = PQntuples(res);
10931
10932         i_amprocnum = PQfnumber(res, "amprocnum");
10933         i_amproc = PQfnumber(res, "amproc");
10934         i_amproclefttype = PQfnumber(res, "amproclefttype");
10935         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10936
10937         for (i = 0; i < ntups; i++)
10938         {
10939                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10940                 amproc = PQgetvalue(res, i, i_amproc);
10941                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10942                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10943
10944                 if (needComma)
10945                         appendPQExpBufferStr(q, " ,\n    ");
10946
10947                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10948
10949                 if (*amproclefttype && *amprocrighttype)
10950                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10951
10952                 appendPQExpBuffer(q, " %s", amproc);
10953
10954                 needComma = true;
10955         }
10956
10957         PQclear(res);
10958
10959         appendPQExpBufferStr(q, ";\n");
10960
10961         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10962                                           fmtId(opcinfo->dobj.name));
10963         appendPQExpBuffer(labelq, " USING %s",
10964                                           fmtId(amname));
10965
10966         if (binary_upgrade)
10967                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10968
10969         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10970                                  opcinfo->dobj.name,
10971                                  opcinfo->dobj.namespace->dobj.name,
10972                                  NULL,
10973                                  opcinfo->rolname,
10974                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10975                                  q->data, delq->data, NULL,
10976                                  NULL, 0,
10977                                  NULL, NULL);
10978
10979         /* Dump Operator Class Comments */
10980         dumpComment(fout, labelq->data,
10981                                 NULL, opcinfo->rolname,
10982                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10983
10984         free(amname);
10985         destroyPQExpBuffer(query);
10986         destroyPQExpBuffer(q);
10987         destroyPQExpBuffer(delq);
10988         destroyPQExpBuffer(labelq);
10989 }
10990
10991 /*
10992  * dumpOpfamily
10993  *        write out a single operator family definition
10994  *
10995  * Note: this also dumps any "loose" operator members that aren't bound to a
10996  * specific opclass within the opfamily.
10997  */
10998 static void
10999 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
11000 {
11001         PQExpBuffer query;
11002         PQExpBuffer q;
11003         PQExpBuffer delq;
11004         PQExpBuffer labelq;
11005         PGresult   *res;
11006         PGresult   *res_ops;
11007         PGresult   *res_procs;
11008         int                     ntups;
11009         int                     i_amname;
11010         int                     i_amopstrategy;
11011         int                     i_amopreqcheck;
11012         int                     i_amopopr;
11013         int                     i_sortfamily;
11014         int                     i_sortfamilynsp;
11015         int                     i_amprocnum;
11016         int                     i_amproc;
11017         int                     i_amproclefttype;
11018         int                     i_amprocrighttype;
11019         char       *amname;
11020         char       *amopstrategy;
11021         char       *amopreqcheck;
11022         char       *amopopr;
11023         char       *sortfamily;
11024         char       *sortfamilynsp;
11025         char       *amprocnum;
11026         char       *amproc;
11027         char       *amproclefttype;
11028         char       *amprocrighttype;
11029         bool            needComma;
11030         int                     i;
11031
11032         /* Skip if not to be dumped */
11033         if (!opfinfo->dobj.dump || dataOnly)
11034                 return;
11035
11036         /*
11037          * We want to dump the opfamily only if (1) it contains "loose" operators
11038          * or functions, or (2) it contains an opclass with a different name or
11039          * owner.  Otherwise it's sufficient to let it be created during creation
11040          * of the contained opclass, and not dumping it improves portability of
11041          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
11042          * that first.
11043          */
11044
11045         query = createPQExpBuffer();
11046         q = createPQExpBuffer();
11047         delq = createPQExpBuffer();
11048         labelq = createPQExpBuffer();
11049
11050         /* Make sure we are in proper schema so regoperator works correctly */
11051         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
11052
11053         /*
11054          * Fetch only those opfamily members that are tied directly to the
11055          * opfamily by pg_depend entries.
11056          *
11057          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
11058          * older server's opclass in which it is used.  This is to avoid
11059          * hard-to-detect breakage if a newer pg_dump is used to dump from an
11060          * older server and then reload into that old version.  This can go away
11061          * once 8.3 is so old as to not be of interest to anyone.
11062          */
11063         if (fout->remoteVersion >= 90100)
11064         {
11065                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11066                                                   "amopopr::pg_catalog.regoperator, "
11067                                                   "opfname AS sortfamily, "
11068                                                   "nspname AS sortfamilynsp "
11069                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
11070                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
11071                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
11072                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
11073                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11074                                                   "AND refobjid = '%u'::pg_catalog.oid "
11075                                                   "AND amopfamily = '%u'::pg_catalog.oid "
11076                                                   "ORDER BY amopstrategy",
11077                                                   opfinfo->dobj.catId.oid,
11078                                                   opfinfo->dobj.catId.oid);
11079         }
11080         else if (fout->remoteVersion >= 80400)
11081         {
11082                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11083                                                   "amopopr::pg_catalog.regoperator, "
11084                                                   "NULL AS sortfamily, "
11085                                                   "NULL AS sortfamilynsp "
11086                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11087                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11088                                                   "AND refobjid = '%u'::pg_catalog.oid "
11089                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11090                                                   "AND objid = ao.oid "
11091                                                   "ORDER BY amopstrategy",
11092                                                   opfinfo->dobj.catId.oid);
11093         }
11094         else
11095         {
11096                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
11097                                                   "amopopr::pg_catalog.regoperator, "
11098                                                   "NULL AS sortfamily, "
11099                                                   "NULL AS sortfamilynsp "
11100                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11101                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11102                                                   "AND refobjid = '%u'::pg_catalog.oid "
11103                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11104                                                   "AND objid = ao.oid "
11105                                                   "ORDER BY amopstrategy",
11106                                                   opfinfo->dobj.catId.oid);
11107         }
11108
11109         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11110
11111         resetPQExpBuffer(query);
11112
11113         appendPQExpBuffer(query, "SELECT amprocnum, "
11114                                           "amproc::pg_catalog.regprocedure, "
11115                                           "amproclefttype::pg_catalog.regtype, "
11116                                           "amprocrighttype::pg_catalog.regtype "
11117                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
11118                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11119                                           "AND refobjid = '%u'::pg_catalog.oid "
11120                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
11121                                           "AND objid = ap.oid "
11122                                           "ORDER BY amprocnum",
11123                                           opfinfo->dobj.catId.oid);
11124
11125         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11126
11127         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
11128         {
11129                 /* No loose members, so check contained opclasses */
11130                 resetPQExpBuffer(query);
11131
11132                 appendPQExpBuffer(query, "SELECT 1 "
11133                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
11134                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
11135                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11136                                                   "AND refobjid = f.oid "
11137                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11138                                                   "AND objid = c.oid "
11139                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
11140                                                   "LIMIT 1",
11141                                                   opfinfo->dobj.catId.oid);
11142
11143                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11144
11145                 if (PQntuples(res) == 0)
11146                 {
11147                         /* no need to dump it, so bail out */
11148                         PQclear(res);
11149                         PQclear(res_ops);
11150                         PQclear(res_procs);
11151                         destroyPQExpBuffer(query);
11152                         destroyPQExpBuffer(q);
11153                         destroyPQExpBuffer(delq);
11154                         destroyPQExpBuffer(labelq);
11155                         return;
11156                 }
11157
11158                 PQclear(res);
11159         }
11160
11161         /* Get additional fields from the pg_opfamily row */
11162         resetPQExpBuffer(query);
11163
11164         appendPQExpBuffer(query, "SELECT "
11165          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11166                                           "FROM pg_catalog.pg_opfamily "
11167                                           "WHERE oid = '%u'::pg_catalog.oid",
11168                                           opfinfo->dobj.catId.oid);
11169
11170         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11171
11172         i_amname = PQfnumber(res, "amname");
11173
11174         /* amname will still be needed after we PQclear res */
11175         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11176
11177         /*
11178          * DROP must be fully qualified in case same name appears in pg_catalog
11179          */
11180         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11181                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11182         appendPQExpBuffer(delq, ".%s",
11183                                           fmtId(opfinfo->dobj.name));
11184         appendPQExpBuffer(delq, " USING %s;\n",
11185                                           fmtId(amname));
11186
11187         /* Build the fixed portion of the CREATE command */
11188         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11189                                           fmtId(opfinfo->dobj.name));
11190         appendPQExpBuffer(q, " USING %s;\n",
11191                                           fmtId(amname));
11192
11193         PQclear(res);
11194
11195         /* Do we need an ALTER to add loose members? */
11196         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11197         {
11198                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11199                                                   fmtId(opfinfo->dobj.name));
11200                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11201                                                   fmtId(amname));
11202
11203                 needComma = false;
11204
11205                 /*
11206                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11207                  */
11208                 ntups = PQntuples(res_ops);
11209
11210                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11211                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11212                 i_amopopr = PQfnumber(res_ops, "amopopr");
11213                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11214                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11215
11216                 for (i = 0; i < ntups; i++)
11217                 {
11218                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11219                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11220                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11221                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11222                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11223
11224                         if (needComma)
11225                                 appendPQExpBufferStr(q, " ,\n    ");
11226
11227                         appendPQExpBuffer(q, "OPERATOR %s %s",
11228                                                           amopstrategy, amopopr);
11229
11230                         if (strlen(sortfamily) > 0)
11231                         {
11232                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
11233                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11234                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11235                                 appendPQExpBufferStr(q, fmtId(sortfamily));
11236                         }
11237
11238                         if (strcmp(amopreqcheck, "t") == 0)
11239                                 appendPQExpBufferStr(q, " RECHECK");
11240
11241                         needComma = true;
11242                 }
11243
11244                 /*
11245                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11246                  */
11247                 ntups = PQntuples(res_procs);
11248
11249                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11250                 i_amproc = PQfnumber(res_procs, "amproc");
11251                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11252                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11253
11254                 for (i = 0; i < ntups; i++)
11255                 {
11256                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11257                         amproc = PQgetvalue(res_procs, i, i_amproc);
11258                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11259                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11260
11261                         if (needComma)
11262                                 appendPQExpBufferStr(q, " ,\n    ");
11263
11264                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11265                                                           amprocnum, amproclefttype, amprocrighttype,
11266                                                           amproc);
11267
11268                         needComma = true;
11269                 }
11270
11271                 appendPQExpBufferStr(q, ";\n");
11272         }
11273
11274         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11275                                           fmtId(opfinfo->dobj.name));
11276         appendPQExpBuffer(labelq, " USING %s",
11277                                           fmtId(amname));
11278
11279         if (binary_upgrade)
11280                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11281
11282         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11283                                  opfinfo->dobj.name,
11284                                  opfinfo->dobj.namespace->dobj.name,
11285                                  NULL,
11286                                  opfinfo->rolname,
11287                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11288                                  q->data, delq->data, NULL,
11289                                  NULL, 0,
11290                                  NULL, NULL);
11291
11292         /* Dump Operator Family Comments */
11293         dumpComment(fout, labelq->data,
11294                                 NULL, opfinfo->rolname,
11295                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11296
11297         free(amname);
11298         PQclear(res_ops);
11299         PQclear(res_procs);
11300         destroyPQExpBuffer(query);
11301         destroyPQExpBuffer(q);
11302         destroyPQExpBuffer(delq);
11303         destroyPQExpBuffer(labelq);
11304 }
11305
11306 /*
11307  * dumpCollation
11308  *        write out a single collation definition
11309  */
11310 static void
11311 dumpCollation(Archive *fout, CollInfo *collinfo)
11312 {
11313         PQExpBuffer query;
11314         PQExpBuffer q;
11315         PQExpBuffer delq;
11316         PQExpBuffer labelq;
11317         PGresult   *res;
11318         int                     i_collcollate;
11319         int                     i_collctype;
11320         const char *collcollate;
11321         const char *collctype;
11322
11323         /* Skip if not to be dumped */
11324         if (!collinfo->dobj.dump || dataOnly)
11325                 return;
11326
11327         query = createPQExpBuffer();
11328         q = createPQExpBuffer();
11329         delq = createPQExpBuffer();
11330         labelq = createPQExpBuffer();
11331
11332         /* Make sure we are in proper schema */
11333         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11334
11335         /* Get collation-specific details */
11336         appendPQExpBuffer(query, "SELECT "
11337                                           "collcollate, "
11338                                           "collctype "
11339                                           "FROM pg_catalog.pg_collation c "
11340                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11341                                           collinfo->dobj.catId.oid);
11342
11343         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11344
11345         i_collcollate = PQfnumber(res, "collcollate");
11346         i_collctype = PQfnumber(res, "collctype");
11347
11348         collcollate = PQgetvalue(res, 0, i_collcollate);
11349         collctype = PQgetvalue(res, 0, i_collctype);
11350
11351         /*
11352          * DROP must be fully qualified in case same name appears in pg_catalog
11353          */
11354         appendPQExpBuffer(delq, "DROP COLLATION %s",
11355                                           fmtId(collinfo->dobj.namespace->dobj.name));
11356         appendPQExpBuffer(delq, ".%s;\n",
11357                                           fmtId(collinfo->dobj.name));
11358
11359         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11360                                           fmtId(collinfo->dobj.name));
11361         appendStringLiteralAH(q, collcollate, fout);
11362         appendPQExpBufferStr(q, ", lc_ctype = ");
11363         appendStringLiteralAH(q, collctype, fout);
11364         appendPQExpBufferStr(q, ");\n");
11365
11366         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11367
11368         if (binary_upgrade)
11369                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11370
11371         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11372                                  collinfo->dobj.name,
11373                                  collinfo->dobj.namespace->dobj.name,
11374                                  NULL,
11375                                  collinfo->rolname,
11376                                  false, "COLLATION", SECTION_PRE_DATA,
11377                                  q->data, delq->data, NULL,
11378                                  NULL, 0,
11379                                  NULL, NULL);
11380
11381         /* Dump Collation Comments */
11382         dumpComment(fout, labelq->data,
11383                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11384                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11385
11386         PQclear(res);
11387
11388         destroyPQExpBuffer(query);
11389         destroyPQExpBuffer(q);
11390         destroyPQExpBuffer(delq);
11391         destroyPQExpBuffer(labelq);
11392 }
11393
11394 /*
11395  * dumpConversion
11396  *        write out a single conversion definition
11397  */
11398 static void
11399 dumpConversion(Archive *fout, ConvInfo *convinfo)
11400 {
11401         PQExpBuffer query;
11402         PQExpBuffer q;
11403         PQExpBuffer delq;
11404         PQExpBuffer labelq;
11405         PGresult   *res;
11406         int                     i_conforencoding;
11407         int                     i_contoencoding;
11408         int                     i_conproc;
11409         int                     i_condefault;
11410         const char *conforencoding;
11411         const char *contoencoding;
11412         const char *conproc;
11413         bool            condefault;
11414
11415         /* Skip if not to be dumped */
11416         if (!convinfo->dobj.dump || dataOnly)
11417                 return;
11418
11419         query = createPQExpBuffer();
11420         q = createPQExpBuffer();
11421         delq = createPQExpBuffer();
11422         labelq = createPQExpBuffer();
11423
11424         /* Make sure we are in proper schema */
11425         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11426
11427         /* Get conversion-specific details */
11428         appendPQExpBuffer(query, "SELECT "
11429                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11430                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11431                                           "conproc, condefault "
11432                                           "FROM pg_catalog.pg_conversion c "
11433                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11434                                           convinfo->dobj.catId.oid);
11435
11436         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11437
11438         i_conforencoding = PQfnumber(res, "conforencoding");
11439         i_contoencoding = PQfnumber(res, "contoencoding");
11440         i_conproc = PQfnumber(res, "conproc");
11441         i_condefault = PQfnumber(res, "condefault");
11442
11443         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11444         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11445         conproc = PQgetvalue(res, 0, i_conproc);
11446         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11447
11448         /*
11449          * DROP must be fully qualified in case same name appears in pg_catalog
11450          */
11451         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11452                                           fmtId(convinfo->dobj.namespace->dobj.name));
11453         appendPQExpBuffer(delq, ".%s;\n",
11454                                           fmtId(convinfo->dobj.name));
11455
11456         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11457                                           (condefault) ? "DEFAULT " : "",
11458                                           fmtId(convinfo->dobj.name));
11459         appendStringLiteralAH(q, conforencoding, fout);
11460         appendPQExpBufferStr(q, " TO ");
11461         appendStringLiteralAH(q, contoencoding, fout);
11462         /* regproc is automatically quoted in 7.3 and above */
11463         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11464
11465         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11466
11467         if (binary_upgrade)
11468                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11469
11470         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11471                                  convinfo->dobj.name,
11472                                  convinfo->dobj.namespace->dobj.name,
11473                                  NULL,
11474                                  convinfo->rolname,
11475                                  false, "CONVERSION", SECTION_PRE_DATA,
11476                                  q->data, delq->data, NULL,
11477                                  NULL, 0,
11478                                  NULL, NULL);
11479
11480         /* Dump Conversion Comments */
11481         dumpComment(fout, labelq->data,
11482                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11483                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11484
11485         PQclear(res);
11486
11487         destroyPQExpBuffer(query);
11488         destroyPQExpBuffer(q);
11489         destroyPQExpBuffer(delq);
11490         destroyPQExpBuffer(labelq);
11491 }
11492
11493 /*
11494  * format_aggregate_signature: generate aggregate name and argument list
11495  *
11496  * The argument type names are qualified if needed.  The aggregate name
11497  * is never qualified.
11498  */
11499 static char *
11500 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11501 {
11502         PQExpBufferData buf;
11503         int                     j;
11504
11505         initPQExpBuffer(&buf);
11506         if (honor_quotes)
11507                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
11508         else
11509                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
11510
11511         if (agginfo->aggfn.nargs == 0)
11512                 appendPQExpBuffer(&buf, "(*)");
11513         else
11514         {
11515                 appendPQExpBufferChar(&buf, '(');
11516                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11517                 {
11518                         char       *typname;
11519
11520                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11521                                                                                    zeroAsOpaque);
11522
11523                         appendPQExpBuffer(&buf, "%s%s",
11524                                                           (j > 0) ? ", " : "",
11525                                                           typname);
11526                         free(typname);
11527                 }
11528                 appendPQExpBufferChar(&buf, ')');
11529         }
11530         return buf.data;
11531 }
11532
11533 /*
11534  * dumpAgg
11535  *        write out a single aggregate definition
11536  */
11537 static void
11538 dumpAgg(Archive *fout, AggInfo *agginfo)
11539 {
11540         PQExpBuffer query;
11541         PQExpBuffer q;
11542         PQExpBuffer delq;
11543         PQExpBuffer labelq;
11544         PQExpBuffer details;
11545         char       *aggsig;                     /* identity signature */
11546         char       *aggfullsig = NULL;          /* full signature */
11547         char       *aggsig_tag;
11548         PGresult   *res;
11549         int                     i_aggtransfn;
11550         int                     i_aggfinalfn;
11551         int                     i_aggmtransfn;
11552         int                     i_aggminvtransfn;
11553         int                     i_aggmfinalfn;
11554         int                     i_aggfinalextra;
11555         int                     i_aggmfinalextra;
11556         int                     i_aggsortop;
11557         int                     i_hypothetical;
11558         int                     i_aggtranstype;
11559         int                     i_aggtransspace;
11560         int                     i_aggmtranstype;
11561         int                     i_aggmtransspace;
11562         int                     i_agginitval;
11563         int                     i_aggminitval;
11564         int                     i_convertok;
11565         const char *aggtransfn;
11566         const char *aggfinalfn;
11567         const char *aggmtransfn;
11568         const char *aggminvtransfn;
11569         const char *aggmfinalfn;
11570         bool            aggfinalextra;
11571         bool            aggmfinalextra;
11572         const char *aggsortop;
11573         char       *aggsortconvop;
11574         bool            hypothetical;
11575         const char *aggtranstype;
11576         const char *aggtransspace;
11577         const char *aggmtranstype;
11578         const char *aggmtransspace;
11579         const char *agginitval;
11580         const char *aggminitval;
11581         bool            convertok;
11582
11583         /* Skip if not to be dumped */
11584         if (!agginfo->aggfn.dobj.dump || dataOnly)
11585                 return;
11586
11587         query = createPQExpBuffer();
11588         q = createPQExpBuffer();
11589         delq = createPQExpBuffer();
11590         labelq = createPQExpBuffer();
11591         details = createPQExpBuffer();
11592
11593         /* Make sure we are in proper schema */
11594         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11595
11596         /* Get aggregate-specific details */
11597         if (fout->remoteVersion >= 90400)
11598         {
11599                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11600                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11601                                                   "aggmtransfn, aggminvtransfn, aggmfinalfn, "
11602                                                   "aggmtranstype::pg_catalog.regtype, "
11603                                                   "aggfinalextra, aggmfinalextra, "
11604                                                   "aggsortop::pg_catalog.regoperator, "
11605                                                   "(aggkind = 'h') AS hypothetical, "
11606                                                   "aggtransspace, agginitval, "
11607                                                   "aggmtransspace, aggminitval, "
11608                                                   "true AS convertok, "
11609                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11610                  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11611                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11612                                                   "WHERE a.aggfnoid = p.oid "
11613                                                   "AND p.oid = '%u'::pg_catalog.oid",
11614                                                   agginfo->aggfn.dobj.catId.oid);
11615         }
11616         else if (fout->remoteVersion >= 80400)
11617         {
11618                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11619                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11620                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
11621                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
11622                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
11623                                                   "aggsortop::pg_catalog.regoperator, "
11624                                                   "false AS hypothetical, "
11625                                                   "0 AS aggtransspace, agginitval, "
11626                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
11627                                                   "true AS convertok, "
11628                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11629                  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
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 >= 80100)
11636         {
11637                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11638                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11639                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
11640                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
11641                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
11642                                                   "aggsortop::pg_catalog.regoperator, "
11643                                                   "false AS hypothetical, "
11644                                                   "0 AS aggtransspace, agginitval, "
11645                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
11646                                                   "true AS convertok "
11647                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11648                                                   "WHERE a.aggfnoid = p.oid "
11649                                                   "AND p.oid = '%u'::pg_catalog.oid",
11650                                                   agginfo->aggfn.dobj.catId.oid);
11651         }
11652         else if (fout->remoteVersion >= 70300)
11653         {
11654                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11655                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11656                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
11657                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
11658                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
11659                                                   "0 AS aggsortop, "
11660                                                   "false AS hypothetical, "
11661                                                   "0 AS aggtransspace, agginitval, "
11662                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
11663                                                   "true AS convertok "
11664                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11665                                                   "WHERE a.aggfnoid = p.oid "
11666                                                   "AND p.oid = '%u'::pg_catalog.oid",
11667                                                   agginfo->aggfn.dobj.catId.oid);
11668         }
11669         else if (fout->remoteVersion >= 70100)
11670         {
11671                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11672                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11673                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
11674                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
11675                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
11676                                                   "0 AS aggsortop, "
11677                                                   "false AS hypothetical, "
11678                                                   "0 AS aggtransspace, agginitval, "
11679                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
11680                                                   "true AS convertok "
11681                                                   "FROM pg_aggregate "
11682                                                   "WHERE oid = '%u'::oid",
11683                                                   agginfo->aggfn.dobj.catId.oid);
11684         }
11685         else
11686         {
11687                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11688                                                   "aggfinalfn, "
11689                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11690                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
11691                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
11692                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
11693                                                   "0 AS aggsortop, "
11694                                                   "false AS hypothetical, "
11695                                                   "0 AS aggtransspace, agginitval1 AS agginitval, "
11696                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
11697                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11698                                                   "FROM pg_aggregate "
11699                                                   "WHERE oid = '%u'::oid",
11700                                                   agginfo->aggfn.dobj.catId.oid);
11701         }
11702
11703         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11704
11705         i_aggtransfn = PQfnumber(res, "aggtransfn");
11706         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11707         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
11708         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
11709         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
11710         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
11711         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
11712         i_aggsortop = PQfnumber(res, "aggsortop");
11713         i_hypothetical = PQfnumber(res, "hypothetical");
11714         i_aggtranstype = PQfnumber(res, "aggtranstype");
11715         i_aggtransspace = PQfnumber(res, "aggtransspace");
11716         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
11717         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
11718         i_agginitval = PQfnumber(res, "agginitval");
11719         i_aggminitval = PQfnumber(res, "aggminitval");
11720         i_convertok = PQfnumber(res, "convertok");
11721
11722         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11723         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11724         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
11725         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
11726         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
11727         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
11728         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
11729         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11730         hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
11731         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11732         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
11733         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
11734         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
11735         agginitval = PQgetvalue(res, 0, i_agginitval);
11736         aggminitval = PQgetvalue(res, 0, i_aggminitval);
11737         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11738
11739         if (fout->remoteVersion >= 80400)
11740         {
11741                 /* 8.4 or later; we rely on server-side code for most of the work */
11742                 char       *funcargs;
11743                 char       *funciargs;
11744
11745                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11746                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11747                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
11748                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
11749         }
11750         else
11751                 /* pre-8.4, do it ourselves */
11752                 aggsig = format_aggregate_signature(agginfo, fout, true);
11753
11754         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11755
11756         if (!convertok)
11757         {
11758                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11759                                   aggsig);
11760
11761                 if (aggfullsig)
11762                         free(aggfullsig);
11763
11764                 free(aggsig);
11765
11766                 return;
11767         }
11768
11769         if (fout->remoteVersion >= 70300)
11770         {
11771                 /* If using 7.3's regproc or regtype, data is already quoted */
11772                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11773                                                   aggtransfn,
11774                                                   aggtranstype);
11775         }
11776         else if (fout->remoteVersion >= 70100)
11777         {
11778                 /* format_type quotes, regproc does not */
11779                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11780                                                   fmtId(aggtransfn),
11781                                                   aggtranstype);
11782         }
11783         else
11784         {
11785                 /* need quotes all around */
11786                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11787                                                   fmtId(aggtransfn));
11788                 appendPQExpBuffer(details, "    STYPE = %s",
11789                                                   fmtId(aggtranstype));
11790         }
11791
11792         if (strcmp(aggtransspace, "0") != 0)
11793         {
11794                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
11795                                                   aggtransspace);
11796         }
11797
11798         if (!PQgetisnull(res, 0, i_agginitval))
11799         {
11800                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
11801                 appendStringLiteralAH(details, agginitval, fout);
11802         }
11803
11804         if (strcmp(aggfinalfn, "-") != 0)
11805         {
11806                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11807                                                   aggfinalfn);
11808                 if (aggfinalextra)
11809                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
11810         }
11811
11812         if (strcmp(aggmtransfn, "-") != 0)
11813         {
11814                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
11815                                                   aggmtransfn,
11816                                                   aggminvtransfn,
11817                                                   aggmtranstype);
11818         }
11819
11820         if (strcmp(aggmtransspace, "0") != 0)
11821         {
11822                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
11823                                                   aggmtransspace);
11824         }
11825
11826         if (!PQgetisnull(res, 0, i_aggminitval))
11827         {
11828                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
11829                 appendStringLiteralAH(details, aggminitval, fout);
11830         }
11831
11832         if (strcmp(aggmfinalfn, "-") != 0)
11833         {
11834                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
11835                                                   aggmfinalfn);
11836                 if (aggmfinalextra)
11837                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
11838         }
11839
11840         aggsortconvop = convertOperatorReference(fout, aggsortop);
11841         if (aggsortconvop)
11842         {
11843                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11844                                                   aggsortconvop);
11845                 free(aggsortconvop);
11846         }
11847
11848         if (hypothetical)
11849                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
11850
11851         /*
11852          * DROP must be fully qualified in case same name appears in pg_catalog
11853          */
11854         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11855                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11856                                           aggsig);
11857
11858         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11859                                           aggfullsig ? aggfullsig : aggsig, details->data);
11860
11861         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11862
11863         if (binary_upgrade)
11864                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11865
11866         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11867                                  aggsig_tag,
11868                                  agginfo->aggfn.dobj.namespace->dobj.name,
11869                                  NULL,
11870                                  agginfo->aggfn.rolname,
11871                                  false, "AGGREGATE", SECTION_PRE_DATA,
11872                                  q->data, delq->data, NULL,
11873                                  NULL, 0,
11874                                  NULL, NULL);
11875
11876         /* Dump Aggregate Comments */
11877         dumpComment(fout, labelq->data,
11878                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11879                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11880         dumpSecLabel(fout, labelq->data,
11881                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11882                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11883
11884         /*
11885          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11886          * command look like a function's GRANT; in particular this affects the
11887          * syntax for zero-argument aggregates and ordered-set aggregates.
11888          */
11889         free(aggsig);
11890         free(aggsig_tag);
11891
11892         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11893         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11894
11895         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11896                         "FUNCTION",
11897                         aggsig, NULL, aggsig_tag,
11898                         agginfo->aggfn.dobj.namespace->dobj.name,
11899                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11900
11901         free(aggsig);
11902         if (aggfullsig)
11903                 free(aggfullsig);
11904         free(aggsig_tag);
11905
11906         PQclear(res);
11907
11908         destroyPQExpBuffer(query);
11909         destroyPQExpBuffer(q);
11910         destroyPQExpBuffer(delq);
11911         destroyPQExpBuffer(labelq);
11912         destroyPQExpBuffer(details);
11913 }
11914
11915 /*
11916  * dumpTSParser
11917  *        write out a single text search parser
11918  */
11919 static void
11920 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11921 {
11922         PQExpBuffer q;
11923         PQExpBuffer delq;
11924         PQExpBuffer labelq;
11925
11926         /* Skip if not to be dumped */
11927         if (!prsinfo->dobj.dump || dataOnly)
11928                 return;
11929
11930         q = createPQExpBuffer();
11931         delq = createPQExpBuffer();
11932         labelq = createPQExpBuffer();
11933
11934         /* Make sure we are in proper schema */
11935         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11936
11937         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11938                                           fmtId(prsinfo->dobj.name));
11939
11940         appendPQExpBuffer(q, "    START = %s,\n",
11941                                           convertTSFunction(fout, prsinfo->prsstart));
11942         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11943                                           convertTSFunction(fout, prsinfo->prstoken));
11944         appendPQExpBuffer(q, "    END = %s,\n",
11945                                           convertTSFunction(fout, prsinfo->prsend));
11946         if (prsinfo->prsheadline != InvalidOid)
11947                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11948                                                   convertTSFunction(fout, prsinfo->prsheadline));
11949         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11950                                           convertTSFunction(fout, prsinfo->prslextype));
11951
11952         /*
11953          * DROP must be fully qualified in case same name appears in pg_catalog
11954          */
11955         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11956                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11957         appendPQExpBuffer(delq, ".%s;\n",
11958                                           fmtId(prsinfo->dobj.name));
11959
11960         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11961                                           fmtId(prsinfo->dobj.name));
11962
11963         if (binary_upgrade)
11964                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11965
11966         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11967                                  prsinfo->dobj.name,
11968                                  prsinfo->dobj.namespace->dobj.name,
11969                                  NULL,
11970                                  "",
11971                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11972                                  q->data, delq->data, NULL,
11973                                  NULL, 0,
11974                                  NULL, NULL);
11975
11976         /* Dump Parser Comments */
11977         dumpComment(fout, labelq->data,
11978                                 NULL, "",
11979                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11980
11981         destroyPQExpBuffer(q);
11982         destroyPQExpBuffer(delq);
11983         destroyPQExpBuffer(labelq);
11984 }
11985
11986 /*
11987  * dumpTSDictionary
11988  *        write out a single text search dictionary
11989  */
11990 static void
11991 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11992 {
11993         PQExpBuffer q;
11994         PQExpBuffer delq;
11995         PQExpBuffer labelq;
11996         PQExpBuffer query;
11997         PGresult   *res;
11998         char       *nspname;
11999         char       *tmplname;
12000
12001         /* Skip if not to be dumped */
12002         if (!dictinfo->dobj.dump || dataOnly)
12003                 return;
12004
12005         q = createPQExpBuffer();
12006         delq = createPQExpBuffer();
12007         labelq = createPQExpBuffer();
12008         query = createPQExpBuffer();
12009
12010         /* Fetch name and namespace of the dictionary's template */
12011         selectSourceSchema(fout, "pg_catalog");
12012         appendPQExpBuffer(query, "SELECT nspname, tmplname "
12013                                           "FROM pg_ts_template p, pg_namespace n "
12014                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
12015                                           dictinfo->dicttemplate);
12016         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12017         nspname = PQgetvalue(res, 0, 0);
12018         tmplname = PQgetvalue(res, 0, 1);
12019
12020         /* Make sure we are in proper schema */
12021         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
12022
12023         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
12024                                           fmtId(dictinfo->dobj.name));
12025
12026         appendPQExpBufferStr(q, "    TEMPLATE = ");
12027         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
12028                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
12029         appendPQExpBufferStr(q, fmtId(tmplname));
12030
12031         PQclear(res);
12032
12033         /* the dictinitoption can be dumped straight into the command */
12034         if (dictinfo->dictinitoption)
12035                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
12036
12037         appendPQExpBufferStr(q, " );\n");
12038
12039         /*
12040          * DROP must be fully qualified in case same name appears in pg_catalog
12041          */
12042         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
12043                                           fmtId(dictinfo->dobj.namespace->dobj.name));
12044         appendPQExpBuffer(delq, ".%s;\n",
12045                                           fmtId(dictinfo->dobj.name));
12046
12047         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
12048                                           fmtId(dictinfo->dobj.name));
12049
12050         if (binary_upgrade)
12051                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
12052
12053         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
12054                                  dictinfo->dobj.name,
12055                                  dictinfo->dobj.namespace->dobj.name,
12056                                  NULL,
12057                                  dictinfo->rolname,
12058                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
12059                                  q->data, delq->data, NULL,
12060                                  NULL, 0,
12061                                  NULL, NULL);
12062
12063         /* Dump Dictionary Comments */
12064         dumpComment(fout, labelq->data,
12065                                 NULL, dictinfo->rolname,
12066                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
12067
12068         destroyPQExpBuffer(q);
12069         destroyPQExpBuffer(delq);
12070         destroyPQExpBuffer(labelq);
12071         destroyPQExpBuffer(query);
12072 }
12073
12074 /*
12075  * dumpTSTemplate
12076  *        write out a single text search template
12077  */
12078 static void
12079 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
12080 {
12081         PQExpBuffer q;
12082         PQExpBuffer delq;
12083         PQExpBuffer labelq;
12084
12085         /* Skip if not to be dumped */
12086         if (!tmplinfo->dobj.dump || dataOnly)
12087                 return;
12088
12089         q = createPQExpBuffer();
12090         delq = createPQExpBuffer();
12091         labelq = createPQExpBuffer();
12092
12093         /* Make sure we are in proper schema */
12094         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
12095
12096         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
12097                                           fmtId(tmplinfo->dobj.name));
12098
12099         if (tmplinfo->tmplinit != InvalidOid)
12100                 appendPQExpBuffer(q, "    INIT = %s,\n",
12101                                                   convertTSFunction(fout, tmplinfo->tmplinit));
12102         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
12103                                           convertTSFunction(fout, tmplinfo->tmpllexize));
12104
12105         /*
12106          * DROP must be fully qualified in case same name appears in pg_catalog
12107          */
12108         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
12109                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
12110         appendPQExpBuffer(delq, ".%s;\n",
12111                                           fmtId(tmplinfo->dobj.name));
12112
12113         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
12114                                           fmtId(tmplinfo->dobj.name));
12115
12116         if (binary_upgrade)
12117                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
12118
12119         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
12120                                  tmplinfo->dobj.name,
12121                                  tmplinfo->dobj.namespace->dobj.name,
12122                                  NULL,
12123                                  "",
12124                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
12125                                  q->data, delq->data, NULL,
12126                                  NULL, 0,
12127                                  NULL, NULL);
12128
12129         /* Dump Template Comments */
12130         dumpComment(fout, labelq->data,
12131                                 NULL, "",
12132                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
12133
12134         destroyPQExpBuffer(q);
12135         destroyPQExpBuffer(delq);
12136         destroyPQExpBuffer(labelq);
12137 }
12138
12139 /*
12140  * dumpTSConfig
12141  *        write out a single text search configuration
12142  */
12143 static void
12144 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
12145 {
12146         PQExpBuffer q;
12147         PQExpBuffer delq;
12148         PQExpBuffer labelq;
12149         PQExpBuffer query;
12150         PGresult   *res;
12151         char       *nspname;
12152         char       *prsname;
12153         int                     ntups,
12154                                 i;
12155         int                     i_tokenname;
12156         int                     i_dictname;
12157
12158         /* Skip if not to be dumped */
12159         if (!cfginfo->dobj.dump || dataOnly)
12160                 return;
12161
12162         q = createPQExpBuffer();
12163         delq = createPQExpBuffer();
12164         labelq = createPQExpBuffer();
12165         query = createPQExpBuffer();
12166
12167         /* Fetch name and namespace of the config's parser */
12168         selectSourceSchema(fout, "pg_catalog");
12169         appendPQExpBuffer(query, "SELECT nspname, prsname "
12170                                           "FROM pg_ts_parser p, pg_namespace n "
12171                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
12172                                           cfginfo->cfgparser);
12173         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12174         nspname = PQgetvalue(res, 0, 0);
12175         prsname = PQgetvalue(res, 0, 1);
12176
12177         /* Make sure we are in proper schema */
12178         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
12179
12180         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
12181                                           fmtId(cfginfo->dobj.name));
12182
12183         appendPQExpBufferStr(q, "    PARSER = ");
12184         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
12185                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
12186         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
12187
12188         PQclear(res);
12189
12190         resetPQExpBuffer(query);
12191         appendPQExpBuffer(query,
12192                                           "SELECT \n"
12193                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
12194                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
12195                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
12196                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
12197                                           "WHERE m.mapcfg = '%u' \n"
12198                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
12199                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
12200
12201         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12202         ntups = PQntuples(res);
12203
12204         i_tokenname = PQfnumber(res, "tokenname");
12205         i_dictname = PQfnumber(res, "dictname");
12206
12207         for (i = 0; i < ntups; i++)
12208         {
12209                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
12210                 char       *dictname = PQgetvalue(res, i, i_dictname);
12211
12212                 if (i == 0 ||
12213                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
12214                 {
12215                         /* starting a new token type, so start a new command */
12216                         if (i > 0)
12217                                 appendPQExpBufferStr(q, ";\n");
12218                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
12219                                                           fmtId(cfginfo->dobj.name));
12220                         /* tokenname needs quoting, dictname does NOT */
12221                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
12222                                                           fmtId(tokenname), dictname);
12223                 }
12224                 else
12225                         appendPQExpBuffer(q, ", %s", dictname);
12226         }
12227
12228         if (ntups > 0)
12229                 appendPQExpBufferStr(q, ";\n");
12230
12231         PQclear(res);
12232
12233         /*
12234          * DROP must be fully qualified in case same name appears in pg_catalog
12235          */
12236         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
12237                                           fmtId(cfginfo->dobj.namespace->dobj.name));
12238         appendPQExpBuffer(delq, ".%s;\n",
12239                                           fmtId(cfginfo->dobj.name));
12240
12241         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
12242                                           fmtId(cfginfo->dobj.name));
12243
12244         if (binary_upgrade)
12245                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
12246
12247         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
12248                                  cfginfo->dobj.name,
12249                                  cfginfo->dobj.namespace->dobj.name,
12250                                  NULL,
12251                                  cfginfo->rolname,
12252                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
12253                                  q->data, delq->data, NULL,
12254                                  NULL, 0,
12255                                  NULL, NULL);
12256
12257         /* Dump Configuration Comments */
12258         dumpComment(fout, labelq->data,
12259                                 NULL, cfginfo->rolname,
12260                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
12261
12262         destroyPQExpBuffer(q);
12263         destroyPQExpBuffer(delq);
12264         destroyPQExpBuffer(labelq);
12265         destroyPQExpBuffer(query);
12266 }
12267
12268 /*
12269  * dumpForeignDataWrapper
12270  *        write out a single foreign-data wrapper definition
12271  */
12272 static void
12273 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
12274 {
12275         PQExpBuffer q;
12276         PQExpBuffer delq;
12277         PQExpBuffer labelq;
12278         char       *qfdwname;
12279
12280         /* Skip if not to be dumped */
12281         if (!fdwinfo->dobj.dump || dataOnly)
12282                 return;
12283
12284         /*
12285          * FDWs that belong to an extension are dumped based on their "dump"
12286          * field. Otherwise omit them if we are only dumping some specific object.
12287          */
12288         if (!fdwinfo->dobj.ext_member)
12289                 if (!include_everything)
12290                         return;
12291
12292         q = createPQExpBuffer();
12293         delq = createPQExpBuffer();
12294         labelq = createPQExpBuffer();
12295
12296         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
12297
12298         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
12299                                           qfdwname);
12300
12301         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
12302                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
12303
12304         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
12305                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
12306
12307         if (strlen(fdwinfo->fdwoptions) > 0)
12308                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12309
12310         appendPQExpBufferStr(q, ";\n");
12311
12312         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12313                                           qfdwname);
12314
12315         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12316                                           qfdwname);
12317
12318         if (binary_upgrade)
12319                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12320
12321         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12322                                  fdwinfo->dobj.name,
12323                                  NULL,
12324                                  NULL,
12325                                  fdwinfo->rolname,
12326                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12327                                  q->data, delq->data, NULL,
12328                                  NULL, 0,
12329                                  NULL, NULL);
12330
12331         /* Handle the ACL */
12332         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12333                         "FOREIGN DATA WRAPPER",
12334                         qfdwname, NULL, fdwinfo->dobj.name,
12335                         NULL, fdwinfo->rolname,
12336                         fdwinfo->fdwacl);
12337
12338         /* Dump Foreign Data Wrapper Comments */
12339         dumpComment(fout, labelq->data,
12340                                 NULL, fdwinfo->rolname,
12341                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12342
12343         free(qfdwname);
12344
12345         destroyPQExpBuffer(q);
12346         destroyPQExpBuffer(delq);
12347         destroyPQExpBuffer(labelq);
12348 }
12349
12350 /*
12351  * dumpForeignServer
12352  *        write out a foreign server definition
12353  */
12354 static void
12355 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12356 {
12357         PQExpBuffer q;
12358         PQExpBuffer delq;
12359         PQExpBuffer labelq;
12360         PQExpBuffer query;
12361         PGresult   *res;
12362         char       *qsrvname;
12363         char       *fdwname;
12364
12365         /* Skip if not to be dumped */
12366         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12367                 return;
12368
12369         q = createPQExpBuffer();
12370         delq = createPQExpBuffer();
12371         labelq = createPQExpBuffer();
12372         query = createPQExpBuffer();
12373
12374         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12375
12376         /* look up the foreign-data wrapper */
12377         selectSourceSchema(fout, "pg_catalog");
12378         appendPQExpBuffer(query, "SELECT fdwname "
12379                                           "FROM pg_foreign_data_wrapper w "
12380                                           "WHERE w.oid = '%u'",
12381                                           srvinfo->srvfdw);
12382         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12383         fdwname = PQgetvalue(res, 0, 0);
12384
12385         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12386         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12387         {
12388                 appendPQExpBufferStr(q, " TYPE ");
12389                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12390         }
12391         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12392         {
12393                 appendPQExpBufferStr(q, " VERSION ");
12394                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12395         }
12396
12397         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
12398         appendPQExpBufferStr(q, fmtId(fdwname));
12399
12400         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12401                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12402
12403         appendPQExpBufferStr(q, ";\n");
12404
12405         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12406                                           qsrvname);
12407
12408         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12409
12410         if (binary_upgrade)
12411                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12412
12413         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12414                                  srvinfo->dobj.name,
12415                                  NULL,
12416                                  NULL,
12417                                  srvinfo->rolname,
12418                                  false, "SERVER", SECTION_PRE_DATA,
12419                                  q->data, delq->data, NULL,
12420                                  NULL, 0,
12421                                  NULL, NULL);
12422
12423         /* Handle the ACL */
12424         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12425                         "FOREIGN SERVER",
12426                         qsrvname, NULL, srvinfo->dobj.name,
12427                         NULL, srvinfo->rolname,
12428                         srvinfo->srvacl);
12429
12430         /* Dump user mappings */
12431         dumpUserMappings(fout,
12432                                          srvinfo->dobj.name, NULL,
12433                                          srvinfo->rolname,
12434                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12435
12436         /* Dump Foreign Server Comments */
12437         dumpComment(fout, labelq->data,
12438                                 NULL, srvinfo->rolname,
12439                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12440
12441         free(qsrvname);
12442
12443         destroyPQExpBuffer(q);
12444         destroyPQExpBuffer(delq);
12445         destroyPQExpBuffer(labelq);
12446 }
12447
12448 /*
12449  * dumpUserMappings
12450  *
12451  * This routine is used to dump any user mappings associated with the
12452  * server handed to this routine. Should be called after ArchiveEntry()
12453  * for the server.
12454  */
12455 static void
12456 dumpUserMappings(Archive *fout,
12457                                  const char *servername, const char *namespace,
12458                                  const char *owner,
12459                                  CatalogId catalogId, DumpId dumpId)
12460 {
12461         PQExpBuffer q;
12462         PQExpBuffer delq;
12463         PQExpBuffer query;
12464         PQExpBuffer tag;
12465         PGresult   *res;
12466         int                     ntups;
12467         int                     i_usename;
12468         int                     i_umoptions;
12469         int                     i;
12470
12471         q = createPQExpBuffer();
12472         tag = createPQExpBuffer();
12473         delq = createPQExpBuffer();
12474         query = createPQExpBuffer();
12475
12476         /*
12477          * We read from the publicly accessible view pg_user_mappings, so as not
12478          * to fail if run by a non-superuser.  Note that the view will show
12479          * umoptions as null if the user hasn't got privileges for the associated
12480          * server; this means that pg_dump will dump such a mapping, but with no
12481          * OPTIONS clause.  A possible alternative is to skip such mappings
12482          * altogether, but it's not clear that that's an improvement.
12483          */
12484         selectSourceSchema(fout, "pg_catalog");
12485
12486         appendPQExpBuffer(query,
12487                                           "SELECT usename, "
12488                                           "array_to_string(ARRAY("
12489                                           "SELECT quote_ident(option_name) || ' ' || "
12490                                           "quote_literal(option_value) "
12491                                           "FROM pg_options_to_table(umoptions) "
12492                                           "ORDER BY option_name"
12493                                           "), E',\n    ') AS umoptions "
12494                                           "FROM pg_user_mappings "
12495                                           "WHERE srvid = '%u' "
12496                                           "ORDER BY usename",
12497                                           catalogId.oid);
12498
12499         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12500
12501         ntups = PQntuples(res);
12502         i_usename = PQfnumber(res, "usename");
12503         i_umoptions = PQfnumber(res, "umoptions");
12504
12505         for (i = 0; i < ntups; i++)
12506         {
12507                 char       *usename;
12508                 char       *umoptions;
12509
12510                 usename = PQgetvalue(res, i, i_usename);
12511                 umoptions = PQgetvalue(res, i, i_umoptions);
12512
12513                 resetPQExpBuffer(q);
12514                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12515                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12516
12517                 if (umoptions && strlen(umoptions) > 0)
12518                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12519
12520                 appendPQExpBufferStr(q, ";\n");
12521
12522                 resetPQExpBuffer(delq);
12523                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12524                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12525
12526                 resetPQExpBuffer(tag);
12527                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12528                                                   usename, servername);
12529
12530                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12531                                          tag->data,
12532                                          namespace,
12533                                          NULL,
12534                                          owner, false,
12535                                          "USER MAPPING", SECTION_PRE_DATA,
12536                                          q->data, delq->data, NULL,
12537                                          &dumpId, 1,
12538                                          NULL, NULL);
12539         }
12540
12541         PQclear(res);
12542
12543         destroyPQExpBuffer(query);
12544         destroyPQExpBuffer(delq);
12545         destroyPQExpBuffer(tag);
12546         destroyPQExpBuffer(q);
12547 }
12548
12549 /*
12550  * Write out default privileges information
12551  */
12552 static void
12553 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12554 {
12555         PQExpBuffer q;
12556         PQExpBuffer tag;
12557         const char *type;
12558
12559         /* Skip if not to be dumped */
12560         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12561                 return;
12562
12563         q = createPQExpBuffer();
12564         tag = createPQExpBuffer();
12565
12566         switch (daclinfo->defaclobjtype)
12567         {
12568                 case DEFACLOBJ_RELATION:
12569                         type = "TABLES";
12570                         break;
12571                 case DEFACLOBJ_SEQUENCE:
12572                         type = "SEQUENCES";
12573                         break;
12574                 case DEFACLOBJ_FUNCTION:
12575                         type = "FUNCTIONS";
12576                         break;
12577                 case DEFACLOBJ_TYPE:
12578                         type = "TYPES";
12579                         break;
12580                 default:
12581                         /* shouldn't get here */
12582                         exit_horribly(NULL,
12583                                           "unrecognized object type in default privileges: %d\n",
12584                                                   (int) daclinfo->defaclobjtype);
12585                         type = "";                      /* keep compiler quiet */
12586         }
12587
12588         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12589
12590         /* build the actual command(s) for this tuple */
12591         if (!buildDefaultACLCommands(type,
12592                                                                  daclinfo->dobj.namespace != NULL ?
12593                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12594                                                                  daclinfo->defaclacl,
12595                                                                  daclinfo->defaclrole,
12596                                                                  fout->remoteVersion,
12597                                                                  q))
12598                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12599                                           daclinfo->defaclacl);
12600
12601         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12602                                  tag->data,
12603            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12604                                  NULL,
12605                                  daclinfo->defaclrole,
12606                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12607                                  q->data, "", NULL,
12608                                  NULL, 0,
12609                                  NULL, NULL);
12610
12611         destroyPQExpBuffer(tag);
12612         destroyPQExpBuffer(q);
12613 }
12614
12615 /*----------
12616  * Write out grant/revoke information
12617  *
12618  * 'objCatId' is the catalog ID of the underlying object.
12619  * 'objDumpId' is the dump ID of the underlying object.
12620  * 'type' must be one of
12621  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12622  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12623  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12624  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12625  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12626  * 'nspname' is the namespace the object is in (NULL if none).
12627  * 'owner' is the owner, NULL if there is no owner (for languages).
12628  * 'acls' is the string read out of the fooacl system catalog field;
12629  *              it will be parsed here.
12630  *----------
12631  */
12632 static void
12633 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12634                 const char *type, const char *name, const char *subname,
12635                 const char *tag, const char *nspname, const char *owner,
12636                 const char *acls)
12637 {
12638         PQExpBuffer sql;
12639
12640         /* Do nothing if ACL dump is not enabled */
12641         if (aclsSkip)
12642                 return;
12643
12644         /* --data-only skips ACLs *except* BLOB ACLs */
12645         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12646                 return;
12647
12648         sql = createPQExpBuffer();
12649
12650         if (!buildACLCommands(name, subname, type, acls, owner,
12651                                                   "", fout->remoteVersion, sql))
12652                 exit_horribly(NULL,
12653                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12654                                           acls, name, type);
12655
12656         if (sql->len > 0)
12657                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12658                                          tag, nspname,
12659                                          NULL,
12660                                          owner ? owner : "",
12661                                          false, "ACL", SECTION_NONE,
12662                                          sql->data, "", NULL,
12663                                          &(objDumpId), 1,
12664                                          NULL, NULL);
12665
12666         destroyPQExpBuffer(sql);
12667 }
12668
12669 /*
12670  * dumpSecLabel
12671  *
12672  * This routine is used to dump any security labels associated with the
12673  * object handed to this routine. The routine takes a constant character
12674  * string for the target part of the security-label command, plus
12675  * the namespace and owner of the object (for labeling the ArchiveEntry),
12676  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12677  * plus the dump ID for the object (for setting a dependency).
12678  * If a matching pg_seclabel entry is found, it is dumped.
12679  *
12680  * Note: although this routine takes a dumpId for dependency purposes,
12681  * that purpose is just to mark the dependency in the emitted dump file
12682  * for possible future use by pg_restore.  We do NOT use it for determining
12683  * ordering of the label in the dump file, because this routine is called
12684  * after dependency sorting occurs.  This routine should be called just after
12685  * calling ArchiveEntry() for the specified object.
12686  */
12687 static void
12688 dumpSecLabel(Archive *fout, const char *target,
12689                          const char *namespace, const char *owner,
12690                          CatalogId catalogId, int subid, DumpId dumpId)
12691 {
12692         SecLabelItem *labels;
12693         int                     nlabels;
12694         int                     i;
12695         PQExpBuffer query;
12696
12697         /* do nothing, if --no-security-labels is supplied */
12698         if (no_security_labels)
12699                 return;
12700
12701         /* Comments are schema not data ... except blob comments are data */
12702         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12703         {
12704                 if (dataOnly)
12705                         return;
12706         }
12707         else
12708         {
12709                 if (schemaOnly)
12710                         return;
12711         }
12712
12713         /* Search for security labels associated with catalogId, using table */
12714         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12715
12716         query = createPQExpBuffer();
12717
12718         for (i = 0; i < nlabels; i++)
12719         {
12720                 /*
12721                  * Ignore label entries for which the subid doesn't match.
12722                  */
12723                 if (labels[i].objsubid != subid)
12724                         continue;
12725
12726                 appendPQExpBuffer(query,
12727                                                   "SECURITY LABEL FOR %s ON %s IS ",
12728                                                   fmtId(labels[i].provider), target);
12729                 appendStringLiteralAH(query, labels[i].label, fout);
12730                 appendPQExpBufferStr(query, ";\n");
12731         }
12732
12733         if (query->len > 0)
12734         {
12735                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12736                                          target, namespace, NULL, owner,
12737                                          false, "SECURITY LABEL", SECTION_NONE,
12738                                          query->data, "", NULL,
12739                                          &(dumpId), 1,
12740                                          NULL, NULL);
12741         }
12742         destroyPQExpBuffer(query);
12743 }
12744
12745 /*
12746  * dumpTableSecLabel
12747  *
12748  * As above, but dump security label for both the specified table (or view)
12749  * and its columns.
12750  */
12751 static void
12752 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12753 {
12754         SecLabelItem *labels;
12755         int                     nlabels;
12756         int                     i;
12757         PQExpBuffer query;
12758         PQExpBuffer target;
12759
12760         /* do nothing, if --no-security-labels is supplied */
12761         if (no_security_labels)
12762                 return;
12763
12764         /* SecLabel are SCHEMA not data */
12765         if (dataOnly)
12766                 return;
12767
12768         /* Search for comments associated with relation, using table */
12769         nlabels = findSecLabels(fout,
12770                                                         tbinfo->dobj.catId.tableoid,
12771                                                         tbinfo->dobj.catId.oid,
12772                                                         &labels);
12773
12774         /* If security labels exist, build SECURITY LABEL statements */
12775         if (nlabels <= 0)
12776                 return;
12777
12778         query = createPQExpBuffer();
12779         target = createPQExpBuffer();
12780
12781         for (i = 0; i < nlabels; i++)
12782         {
12783                 const char *colname;
12784                 const char *provider = labels[i].provider;
12785                 const char *label = labels[i].label;
12786                 int                     objsubid = labels[i].objsubid;
12787
12788                 resetPQExpBuffer(target);
12789                 if (objsubid == 0)
12790                 {
12791                         appendPQExpBuffer(target, "%s %s", reltypename,
12792                                                           fmtId(tbinfo->dobj.name));
12793                 }
12794                 else
12795                 {
12796                         colname = getAttrName(objsubid, tbinfo);
12797                         /* first fmtId result must be consumed before calling it again */
12798                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12799                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12800                 }
12801                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12802                                                   fmtId(provider), target->data);
12803                 appendStringLiteralAH(query, label, fout);
12804                 appendPQExpBufferStr(query, ";\n");
12805         }
12806         if (query->len > 0)
12807         {
12808                 resetPQExpBuffer(target);
12809                 appendPQExpBuffer(target, "%s %s", reltypename,
12810                                                   fmtId(tbinfo->dobj.name));
12811                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12812                                          target->data,
12813                                          tbinfo->dobj.namespace->dobj.name,
12814                                          NULL, tbinfo->rolname,
12815                                          false, "SECURITY LABEL", SECTION_NONE,
12816                                          query->data, "", NULL,
12817                                          &(tbinfo->dobj.dumpId), 1,
12818                                          NULL, NULL);
12819         }
12820         destroyPQExpBuffer(query);
12821         destroyPQExpBuffer(target);
12822 }
12823
12824 /*
12825  * findSecLabels
12826  *
12827  * Find the security label(s), if any, associated with the given object.
12828  * All the objsubid values associated with the given classoid/objoid are
12829  * found with one search.
12830  */
12831 static int
12832 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12833 {
12834         /* static storage for table of security labels */
12835         static SecLabelItem *labels = NULL;
12836         static int      nlabels = -1;
12837
12838         SecLabelItem *middle = NULL;
12839         SecLabelItem *low;
12840         SecLabelItem *high;
12841         int                     nmatch;
12842
12843         /* Get security labels if we didn't already */
12844         if (nlabels < 0)
12845                 nlabels = collectSecLabels(fout, &labels);
12846
12847         if (nlabels <= 0)                       /* no labels, so no match is possible */
12848         {
12849                 *items = NULL;
12850                 return 0;
12851         }
12852
12853         /*
12854          * Do binary search to find some item matching the object.
12855          */
12856         low = &labels[0];
12857         high = &labels[nlabels - 1];
12858         while (low <= high)
12859         {
12860                 middle = low + (high - low) / 2;
12861
12862                 if (classoid < middle->classoid)
12863                         high = middle - 1;
12864                 else if (classoid > middle->classoid)
12865                         low = middle + 1;
12866                 else if (objoid < middle->objoid)
12867                         high = middle - 1;
12868                 else if (objoid > middle->objoid)
12869                         low = middle + 1;
12870                 else
12871                         break;                          /* found a match */
12872         }
12873
12874         if (low > high)                         /* no matches */
12875         {
12876                 *items = NULL;
12877                 return 0;
12878         }
12879
12880         /*
12881          * Now determine how many items match the object.  The search loop
12882          * invariant still holds: only items between low and high inclusive could
12883          * match.
12884          */
12885         nmatch = 1;
12886         while (middle > low)
12887         {
12888                 if (classoid != middle[-1].classoid ||
12889                         objoid != middle[-1].objoid)
12890                         break;
12891                 middle--;
12892                 nmatch++;
12893         }
12894
12895         *items = middle;
12896
12897         middle += nmatch;
12898         while (middle <= high)
12899         {
12900                 if (classoid != middle->classoid ||
12901                         objoid != middle->objoid)
12902                         break;
12903                 middle++;
12904                 nmatch++;
12905         }
12906
12907         return nmatch;
12908 }
12909
12910 /*
12911  * collectSecLabels
12912  *
12913  * Construct a table of all security labels available for database objects.
12914  * It's much faster to pull them all at once.
12915  *
12916  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12917  */
12918 static int
12919 collectSecLabels(Archive *fout, SecLabelItem **items)
12920 {
12921         PGresult   *res;
12922         PQExpBuffer query;
12923         int                     i_label;
12924         int                     i_provider;
12925         int                     i_classoid;
12926         int                     i_objoid;
12927         int                     i_objsubid;
12928         int                     ntups;
12929         int                     i;
12930         SecLabelItem *labels;
12931
12932         query = createPQExpBuffer();
12933
12934         appendPQExpBufferStr(query,
12935                                                  "SELECT label, provider, classoid, objoid, objsubid "
12936                                                  "FROM pg_catalog.pg_seclabel "
12937                                                  "ORDER BY classoid, objoid, objsubid");
12938
12939         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12940
12941         /* Construct lookup table containing OIDs in numeric form */
12942         i_label = PQfnumber(res, "label");
12943         i_provider = PQfnumber(res, "provider");
12944         i_classoid = PQfnumber(res, "classoid");
12945         i_objoid = PQfnumber(res, "objoid");
12946         i_objsubid = PQfnumber(res, "objsubid");
12947
12948         ntups = PQntuples(res);
12949
12950         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12951
12952         for (i = 0; i < ntups; i++)
12953         {
12954                 labels[i].label = PQgetvalue(res, i, i_label);
12955                 labels[i].provider = PQgetvalue(res, i, i_provider);
12956                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12957                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12958                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12959         }
12960
12961         /* Do NOT free the PGresult since we are keeping pointers into it */
12962         destroyPQExpBuffer(query);
12963
12964         *items = labels;
12965         return ntups;
12966 }
12967
12968 /*
12969  * dumpTable
12970  *        write out to fout the declarations (not data) of a user-defined table
12971  */
12972 static void
12973 dumpTable(Archive *fout, TableInfo *tbinfo)
12974 {
12975         if (tbinfo->dobj.dump && !dataOnly)
12976         {
12977                 char       *namecopy;
12978
12979                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12980                         dumpSequence(fout, tbinfo);
12981                 else
12982                         dumpTableSchema(fout, tbinfo);
12983
12984                 /* Handle the ACL here */
12985                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12986                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12987                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12988                                 "TABLE",
12989                                 namecopy, NULL, tbinfo->dobj.name,
12990                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12991                                 tbinfo->relacl);
12992
12993                 /*
12994                  * Handle column ACLs, if any.  Note: we pull these with a separate
12995                  * query rather than trying to fetch them during getTableAttrs, so
12996                  * that we won't miss ACLs on system columns.
12997                  */
12998                 if (fout->remoteVersion >= 80400)
12999                 {
13000                         PQExpBuffer query = createPQExpBuffer();
13001                         PGresult   *res;
13002                         int                     i;
13003
13004                         appendPQExpBuffer(query,
13005                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
13006                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
13007                                                           "ORDER BY attnum",
13008                                                           tbinfo->dobj.catId.oid);
13009                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13010
13011                         for (i = 0; i < PQntuples(res); i++)
13012                         {
13013                                 char       *attname = PQgetvalue(res, i, 0);
13014                                 char       *attacl = PQgetvalue(res, i, 1);
13015                                 char       *attnamecopy;
13016                                 char       *acltag;
13017
13018                                 attnamecopy = pg_strdup(fmtId(attname));
13019                                 acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
13020                                 /* Column's GRANT type is always TABLE */
13021                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
13022                                                 namecopy, attnamecopy, acltag,
13023                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13024                                                 attacl);
13025                                 free(attnamecopy);
13026                                 free(acltag);
13027                         }
13028                         PQclear(res);
13029                         destroyPQExpBuffer(query);
13030                 }
13031
13032                 free(namecopy);
13033         }
13034 }
13035
13036 /*
13037  * Create the AS clause for a view or materialized view. The semicolon is
13038  * stripped because a materialized view must add a WITH NO DATA clause.
13039  *
13040  * This returns a new buffer which must be freed by the caller.
13041  */
13042 static PQExpBuffer
13043 createViewAsClause(Archive *fout, TableInfo *tbinfo)
13044 {
13045         PQExpBuffer query = createPQExpBuffer();
13046         PQExpBuffer result = createPQExpBuffer();
13047         PGresult   *res;
13048         int                     len;
13049
13050         /* Fetch the view definition */
13051         if (fout->remoteVersion >= 70300)
13052         {
13053                 /* Beginning in 7.3, viewname is not unique; rely on OID */
13054                 appendPQExpBuffer(query,
13055                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
13056                                                   tbinfo->dobj.catId.oid);
13057         }
13058         else
13059         {
13060                 appendPQExpBufferStr(query, "SELECT definition AS viewdef "
13061                                                          "FROM pg_views WHERE viewname = ");
13062                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
13063         }
13064
13065         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13066
13067         if (PQntuples(res) != 1)
13068         {
13069                 if (PQntuples(res) < 1)
13070                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
13071                                                   tbinfo->dobj.name);
13072                 else
13073                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
13074                                                   tbinfo->dobj.name);
13075         }
13076
13077         len = PQgetlength(res, 0, 0);
13078
13079         if (len == 0)
13080                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
13081                                           tbinfo->dobj.name);
13082
13083         /* Strip off the trailing semicolon so that other things may follow. */
13084         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
13085         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
13086
13087         PQclear(res);
13088         destroyPQExpBuffer(query);
13089
13090         return result;
13091 }
13092
13093 /*
13094  * dumpTableSchema
13095  *        write the declaration (not data) of one user-defined table or view
13096  */
13097 static void
13098 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
13099 {
13100         PQExpBuffer q = createPQExpBuffer();
13101         PQExpBuffer delq = createPQExpBuffer();
13102         PQExpBuffer labelq = createPQExpBuffer();
13103         int                     numParents;
13104         TableInfo **parents;
13105         int                     actual_atts;    /* number of attrs in this CREATE statement */
13106         const char *reltypename;
13107         char       *storage;
13108         char       *srvname;
13109         char       *ftoptions;
13110         int                     j,
13111                                 k;
13112
13113         /* Make sure we are in proper schema */
13114         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13115
13116         if (binary_upgrade)
13117                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
13118                                                                                                 tbinfo->dobj.catId.oid);
13119
13120         /* Is it a table or a view? */
13121         if (tbinfo->relkind == RELKIND_VIEW)
13122         {
13123                 PQExpBuffer result;
13124
13125                 reltypename = "VIEW";
13126
13127                 /*
13128                  * DROP must be fully qualified in case same name appears in
13129                  * pg_catalog
13130                  */
13131                 appendPQExpBuffer(delq, "DROP VIEW %s.",
13132                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13133                 appendPQExpBuffer(delq, "%s;\n",
13134                                                   fmtId(tbinfo->dobj.name));
13135
13136                 if (binary_upgrade)
13137                         binary_upgrade_set_pg_class_oids(fout, q,
13138                                                                                          tbinfo->dobj.catId.oid, false);
13139
13140                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
13141                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13142                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
13143                 result = createViewAsClause(fout, tbinfo);
13144                 appendPQExpBuffer(q, " AS\n%s", result->data);
13145                 destroyPQExpBuffer(result);
13146
13147                 if (tbinfo->checkoption != NULL)
13148                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
13149                 appendPQExpBufferStr(q, ";\n");
13150
13151                 appendPQExpBuffer(labelq, "VIEW %s",
13152                                                   fmtId(tbinfo->dobj.name));
13153         }
13154         else
13155         {
13156                 switch (tbinfo->relkind)
13157                 {
13158                         case (RELKIND_FOREIGN_TABLE):
13159                                 {
13160                                         PQExpBuffer query = createPQExpBuffer();
13161                                         PGresult   *res;
13162                                         int                     i_srvname;
13163                                         int                     i_ftoptions;
13164
13165                                         reltypename = "FOREIGN TABLE";
13166
13167                                         /* retrieve name of foreign server and generic options */
13168                                         appendPQExpBuffer(query,
13169                                                                           "SELECT fs.srvname, "
13170                                                                           "pg_catalog.array_to_string(ARRAY("
13171                                                          "SELECT pg_catalog.quote_ident(option_name) || "
13172                                                          "' ' || pg_catalog.quote_literal(option_value) "
13173                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
13174                                                                           "ORDER BY option_name"
13175                                                                           "), E',\n    ') AS ftoptions "
13176                                                                           "FROM pg_catalog.pg_foreign_table ft "
13177                                                                           "JOIN pg_catalog.pg_foreign_server fs "
13178                                                                           "ON (fs.oid = ft.ftserver) "
13179                                                                           "WHERE ft.ftrelid = '%u'",
13180                                                                           tbinfo->dobj.catId.oid);
13181                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13182                                         i_srvname = PQfnumber(res, "srvname");
13183                                         i_ftoptions = PQfnumber(res, "ftoptions");
13184                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
13185                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
13186                                         PQclear(res);
13187                                         destroyPQExpBuffer(query);
13188                                         break;
13189                                 }
13190                         case (RELKIND_MATVIEW):
13191                                 reltypename = "MATERIALIZED VIEW";
13192                                 srvname = NULL;
13193                                 ftoptions = NULL;
13194                                 break;
13195                         default:
13196                                 reltypename = "TABLE";
13197                                 srvname = NULL;
13198                                 ftoptions = NULL;
13199                 }
13200
13201                 numParents = tbinfo->numParents;
13202                 parents = tbinfo->parents;
13203
13204                 /*
13205                  * DROP must be fully qualified in case same name appears in
13206                  * pg_catalog
13207                  */
13208                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
13209                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13210                 appendPQExpBuffer(delq, "%s;\n",
13211                                                   fmtId(tbinfo->dobj.name));
13212
13213                 appendPQExpBuffer(labelq, "%s %s", reltypename,
13214                                                   fmtId(tbinfo->dobj.name));
13215
13216                 if (binary_upgrade)
13217                         binary_upgrade_set_pg_class_oids(fout, q,
13218                                                                                          tbinfo->dobj.catId.oid, false);
13219
13220                 appendPQExpBuffer(q, "CREATE %s%s %s",
13221                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
13222                                                   "UNLOGGED " : "",
13223                                                   reltypename,
13224                                                   fmtId(tbinfo->dobj.name));
13225
13226                 /*
13227                  * Attach to type, if reloftype; except in case of a binary upgrade,
13228                  * we dump the table normally and attach it to the type afterward.
13229                  */
13230                 if (tbinfo->reloftype && !binary_upgrade)
13231                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
13232
13233                 if (tbinfo->relkind != RELKIND_MATVIEW)
13234                 {
13235                         /* Dump the attributes */
13236                         actual_atts = 0;
13237                         for (j = 0; j < tbinfo->numatts; j++)
13238                         {
13239                                 /*
13240                                  * Normally, dump if it's locally defined in this table, and
13241                                  * not dropped.  But for binary upgrade, we'll dump all the
13242                                  * columns, and then fix up the dropped and nonlocal cases
13243                                  * below.
13244                                  */
13245                                 if (shouldPrintColumn(tbinfo, j))
13246                                 {
13247                                         /*
13248                                          * Default value --- suppress if to be printed separately.
13249                                          */
13250                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
13251                                                                                          !tbinfo->attrdefs[j]->separate);
13252
13253                                         /*
13254                                          * Not Null constraint --- suppress if inherited, except
13255                                          * in binary-upgrade case where that won't work.
13256                                          */
13257                                         bool            has_notnull = (tbinfo->notnull[j] &&
13258                                                                                            (!tbinfo->inhNotNull[j] ||
13259                                                                                                 binary_upgrade));
13260
13261                                         /* Skip column if fully defined by reloftype */
13262                                         if (tbinfo->reloftype &&
13263                                                 !has_default && !has_notnull && !binary_upgrade)
13264                                                 continue;
13265
13266                                         /* Format properly if not first attr */
13267                                         if (actual_atts == 0)
13268                                                 appendPQExpBufferStr(q, " (");
13269                                         else
13270                                                 appendPQExpBufferStr(q, ",");
13271                                         appendPQExpBufferStr(q, "\n    ");
13272                                         actual_atts++;
13273
13274                                         /* Attribute name */
13275                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
13276
13277                                         if (tbinfo->attisdropped[j])
13278                                         {
13279                                                 /*
13280                                                  * ALTER TABLE DROP COLUMN clears
13281                                                  * pg_attribute.atttypid, so we will not have gotten a
13282                                                  * valid type name; insert INTEGER as a stopgap. We'll
13283                                                  * clean things up later.
13284                                                  */
13285                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
13286                                                 /* Skip all the rest, too */
13287                                                 continue;
13288                                         }
13289
13290                                         /* Attribute type */
13291                                         if (tbinfo->reloftype && !binary_upgrade)
13292                                         {
13293                                                 appendPQExpBufferStr(q, " WITH OPTIONS");
13294                                         }
13295                                         else if (fout->remoteVersion >= 70100)
13296                                         {
13297                                                 appendPQExpBuffer(q, " %s",
13298                                                                                   tbinfo->atttypnames[j]);
13299                                         }
13300                                         else
13301                                         {
13302                                                 /* If no format_type, fake it */
13303                                                 appendPQExpBuffer(q, " %s",
13304                                                                                   myFormatType(tbinfo->atttypnames[j],
13305                                                                                                            tbinfo->atttypmod[j]));
13306                                         }
13307
13308                                         /* Add collation if not default for the type */
13309                                         if (OidIsValid(tbinfo->attcollation[j]))
13310                                         {
13311                                                 CollInfo   *coll;
13312
13313                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
13314                                                 if (coll)
13315                                                 {
13316                                                         /* always schema-qualify, don't try to be smart */
13317                                                         appendPQExpBuffer(q, " COLLATE %s.",
13318                                                                          fmtId(coll->dobj.namespace->dobj.name));
13319                                                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
13320                                                 }
13321                                         }
13322
13323                                         if (has_default)
13324                                                 appendPQExpBuffer(q, " DEFAULT %s",
13325                                                                                   tbinfo->attrdefs[j]->adef_expr);
13326
13327                                         if (has_notnull)
13328                                                 appendPQExpBufferStr(q, " NOT NULL");
13329                                 }
13330                         }
13331
13332                         /*
13333                          * Add non-inherited CHECK constraints, if any.
13334                          */
13335                         for (j = 0; j < tbinfo->ncheck; j++)
13336                         {
13337                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13338
13339                                 if (constr->separate || !constr->conislocal)
13340                                         continue;
13341
13342                                 if (actual_atts == 0)
13343                                         appendPQExpBufferStr(q, " (\n    ");
13344                                 else
13345                                         appendPQExpBufferStr(q, ",\n    ");
13346
13347                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13348                                                                   fmtId(constr->dobj.name));
13349                                 appendPQExpBufferStr(q, constr->condef);
13350
13351                                 actual_atts++;
13352                         }
13353
13354                         if (actual_atts)
13355                                 appendPQExpBufferStr(q, "\n)");
13356                         else if (!(tbinfo->reloftype && !binary_upgrade))
13357                         {
13358                                 /*
13359                                  * We must have a parenthesized attribute list, even though
13360                                  * empty, when not using the OF TYPE syntax.
13361                                  */
13362                                 appendPQExpBufferStr(q, " (\n)");
13363                         }
13364
13365                         if (numParents > 0 && !binary_upgrade)
13366                         {
13367                                 appendPQExpBufferStr(q, "\nINHERITS (");
13368                                 for (k = 0; k < numParents; k++)
13369                                 {
13370                                         TableInfo  *parentRel = parents[k];
13371
13372                                         if (k > 0)
13373                                                 appendPQExpBufferStr(q, ", ");
13374                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13375                                                 appendPQExpBuffer(q, "%s.",
13376                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13377                                         appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
13378                                 }
13379                                 appendPQExpBufferChar(q, ')');
13380                         }
13381
13382                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13383                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13384                 }
13385
13386                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13387                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13388                 {
13389                         bool            addcomma = false;
13390
13391                         appendPQExpBufferStr(q, "\nWITH (");
13392                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13393                         {
13394                                 addcomma = true;
13395                                 appendPQExpBufferStr(q, tbinfo->reloptions);
13396                         }
13397                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13398                         {
13399                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13400                                                                   tbinfo->toast_reloptions);
13401                         }
13402                         appendPQExpBufferChar(q, ')');
13403                 }
13404
13405                 /* Dump generic options if any */
13406                 if (ftoptions && ftoptions[0])
13407                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13408
13409                 /*
13410                  * For materialized views, create the AS clause just like a view. At
13411                  * this point, we always mark the view as not populated.
13412                  */
13413                 if (tbinfo->relkind == RELKIND_MATVIEW)
13414                 {
13415                         PQExpBuffer result;
13416
13417                         result = createViewAsClause(fout, tbinfo);
13418                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13419                                                           result->data);
13420                         destroyPQExpBuffer(result);
13421                 }
13422                 else
13423                         appendPQExpBufferStr(q, ";\n");
13424
13425                 /*
13426                  * To create binary-compatible heap files, we have to ensure the same
13427                  * physical column order, including dropped columns, as in the
13428                  * original.  Therefore, we create dropped columns above and drop them
13429                  * here, also updating their attlen/attalign values so that the
13430                  * dropped column can be skipped properly.  (We do not bother with
13431                  * restoring the original attbyval setting.)  Also, inheritance
13432                  * relationships are set up by doing ALTER INHERIT rather than using
13433                  * an INHERITS clause --- the latter would possibly mess up the column
13434                  * order.  That also means we have to take care about setting
13435                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13436                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13437                  */
13438                 if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
13439                                                            tbinfo->relkind == RELKIND_FOREIGN_TABLE))
13440                 {
13441                         for (j = 0; j < tbinfo->numatts; j++)
13442                         {
13443                                 if (tbinfo->attisdropped[j])
13444                                 {
13445                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
13446                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13447                                                                           "SET attlen = %d, "
13448                                                                           "attalign = '%c', attbyval = false\n"
13449                                                                           "WHERE attname = ",
13450                                                                           tbinfo->attlen[j],
13451                                                                           tbinfo->attalign[j]);
13452                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13453                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
13454                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13455                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13456
13457                                         if (tbinfo->relkind == RELKIND_RELATION)
13458                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13459                                                                                   fmtId(tbinfo->dobj.name));
13460                                         else
13461                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13462                                                                                   fmtId(tbinfo->dobj.name));
13463
13464                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13465                                                                           fmtId(tbinfo->attnames[j]));
13466                                 }
13467                                 else if (!tbinfo->attislocal[j])
13468                                 {
13469                                         Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
13470                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
13471                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
13472                                                                                  "SET attislocal = false\n"
13473                                                                                  "WHERE attname = ");
13474                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13475                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
13476                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13477                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13478                                 }
13479                         }
13480
13481                         for (k = 0; k < tbinfo->ncheck; k++)
13482                         {
13483                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13484
13485                                 if (constr->separate || constr->conislocal)
13486                                         continue;
13487
13488                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13489                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13490                                                                   fmtId(tbinfo->dobj.name));
13491                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13492                                                                   fmtId(constr->dobj.name));
13493                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13494                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
13495                                                                          "SET conislocal = false\n"
13496                                                                          "WHERE contype = 'c' AND conname = ");
13497                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13498                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
13499                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13500                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13501                         }
13502
13503                         if (numParents > 0)
13504                         {
13505                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13506                                 for (k = 0; k < numParents; k++)
13507                                 {
13508                                         TableInfo  *parentRel = parents[k];
13509
13510                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13511                                                                           fmtId(tbinfo->dobj.name));
13512                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13513                                                 appendPQExpBuffer(q, "%s.",
13514                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13515                                         appendPQExpBuffer(q, "%s;\n",
13516                                                                           fmtId(parentRel->dobj.name));
13517                                 }
13518                         }
13519
13520                         if (tbinfo->reloftype)
13521                         {
13522                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13523                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13524                                                                   fmtId(tbinfo->dobj.name),
13525                                                                   tbinfo->reloftype);
13526                         }
13527
13528                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13529                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13530                                                           "SET relfrozenxid = '%u'\n"
13531                                                           "WHERE oid = ",
13532                                                           tbinfo->frozenxid);
13533                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13534                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13535
13536                         if (tbinfo->toast_oid)
13537                         {
13538                                 /* We preserve the toast oids, so we can use it during restore */
13539                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13540                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13541                                                                   "SET relfrozenxid = '%u'\n"
13542                                                                   "WHERE oid = '%u';\n",
13543                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13544                         }
13545                 }
13546
13547                 /*
13548                  * In binary_upgrade mode, restore matviews' populated status by
13549                  * poking pg_class directly.  This is pretty ugly, but we can't use
13550                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
13551                  * matview is not populated even though this matview is.
13552                  */
13553                 if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
13554                         tbinfo->relispopulated)
13555                 {
13556                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
13557                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
13558                                                                  "SET relispopulated = 't'\n"
13559                                                                  "WHERE oid = ");
13560                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13561                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13562                 }
13563
13564                 /*
13565                  * Dump additional per-column properties that we can't handle in the
13566                  * main CREATE TABLE command.
13567                  */
13568                 for (j = 0; j < tbinfo->numatts; j++)
13569                 {
13570                         /* None of this applies to dropped columns */
13571                         if (tbinfo->attisdropped[j])
13572                                 continue;
13573
13574                         /*
13575                          * If we didn't dump the column definition explicitly above, and
13576                          * it is NOT NULL and did not inherit that property from a parent,
13577                          * we have to mark it separately.
13578                          */
13579                         if (!shouldPrintColumn(tbinfo, j) &&
13580                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13581                         {
13582                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13583                                                                   fmtId(tbinfo->dobj.name));
13584                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13585                                                                   fmtId(tbinfo->attnames[j]));
13586                         }
13587
13588                         /*
13589                          * Dump per-column statistics information. We only issue an ALTER
13590                          * TABLE statement if the attstattarget entry for this column is
13591                          * non-negative (i.e. it's not the default value)
13592                          */
13593                         if (tbinfo->attstattarget[j] >= 0)
13594                         {
13595                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13596                                                                   fmtId(tbinfo->dobj.name));
13597                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13598                                                                   fmtId(tbinfo->attnames[j]));
13599                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13600                                                                   tbinfo->attstattarget[j]);
13601                         }
13602
13603                         /*
13604                          * Dump per-column storage information.  The statement is only
13605                          * dumped if the storage has been changed from the type's default.
13606                          */
13607                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13608                         {
13609                                 switch (tbinfo->attstorage[j])
13610                                 {
13611                                         case 'p':
13612                                                 storage = "PLAIN";
13613                                                 break;
13614                                         case 'e':
13615                                                 storage = "EXTERNAL";
13616                                                 break;
13617                                         case 'm':
13618                                                 storage = "MAIN";
13619                                                 break;
13620                                         case 'x':
13621                                                 storage = "EXTENDED";
13622                                                 break;
13623                                         default:
13624                                                 storage = NULL;
13625                                 }
13626
13627                                 /*
13628                                  * Only dump the statement if it's a storage type we recognize
13629                                  */
13630                                 if (storage != NULL)
13631                                 {
13632                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13633                                                                           fmtId(tbinfo->dobj.name));
13634                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
13635                                                                           fmtId(tbinfo->attnames[j]));
13636                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
13637                                                                           storage);
13638                                 }
13639                         }
13640
13641                         /*
13642                          * Dump per-column attributes.
13643                          */
13644                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13645                         {
13646                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13647                                                                   fmtId(tbinfo->dobj.name));
13648                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13649                                                                   fmtId(tbinfo->attnames[j]));
13650                                 appendPQExpBuffer(q, "SET (%s);\n",
13651                                                                   tbinfo->attoptions[j]);
13652                         }
13653
13654                         /*
13655                          * Dump per-column fdw options.
13656                          */
13657                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13658                                 tbinfo->attfdwoptions[j] &&
13659                                 tbinfo->attfdwoptions[j][0] != '\0')
13660                         {
13661                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13662                                                                   fmtId(tbinfo->dobj.name));
13663                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13664                                                                   fmtId(tbinfo->attnames[j]));
13665                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13666                                                                   tbinfo->attfdwoptions[j]);
13667                         }
13668                 }
13669         }
13670
13671         /*
13672          * dump properties we only have ALTER TABLE syntax for
13673          */
13674         if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) &&
13675                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
13676         {
13677                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
13678                 {
13679                         /* nothing to do, will be set when the index is dumped */
13680                 }
13681                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
13682                 {
13683                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
13684                                                           fmtId(tbinfo->dobj.name));
13685                 }
13686                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
13687                 {
13688                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
13689                                                           fmtId(tbinfo->dobj.name));
13690                 }
13691         }
13692
13693         if (binary_upgrade)
13694                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13695
13696         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13697                                  tbinfo->dobj.name,
13698                                  tbinfo->dobj.namespace->dobj.name,
13699                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13700                                  tbinfo->rolname,
13701                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13702                                  reltypename,
13703                                  tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
13704                                  q->data, delq->data, NULL,
13705                                  NULL, 0,
13706                                  NULL, NULL);
13707
13708
13709         /* Dump Table Comments */
13710         dumpTableComment(fout, tbinfo, reltypename);
13711
13712         /* Dump Table Security Labels */
13713         dumpTableSecLabel(fout, tbinfo, reltypename);
13714
13715         /* Dump comments on inlined table constraints */
13716         for (j = 0; j < tbinfo->ncheck; j++)
13717         {
13718                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13719
13720                 if (constr->separate || !constr->conislocal)
13721                         continue;
13722
13723                 dumpTableConstraintComment(fout, constr);
13724         }
13725
13726         destroyPQExpBuffer(q);
13727         destroyPQExpBuffer(delq);
13728         destroyPQExpBuffer(labelq);
13729 }
13730
13731 /*
13732  * dumpAttrDef --- dump an attribute's default-value declaration
13733  */
13734 static void
13735 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13736 {
13737         TableInfo  *tbinfo = adinfo->adtable;
13738         int                     adnum = adinfo->adnum;
13739         PQExpBuffer q;
13740         PQExpBuffer delq;
13741
13742         /* Skip if table definition not to be dumped */
13743         if (!tbinfo->dobj.dump || dataOnly)
13744                 return;
13745
13746         /* Skip if not "separate"; it was dumped in the table's definition */
13747         if (!adinfo->separate)
13748                 return;
13749
13750         q = createPQExpBuffer();
13751         delq = createPQExpBuffer();
13752
13753         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13754                                           fmtId(tbinfo->dobj.name));
13755         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13756                                           fmtId(tbinfo->attnames[adnum - 1]),
13757                                           adinfo->adef_expr);
13758
13759         /*
13760          * DROP must be fully qualified in case same name appears in pg_catalog
13761          */
13762         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13763                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13764         appendPQExpBuffer(delq, "%s ",
13765                                           fmtId(tbinfo->dobj.name));
13766         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13767                                           fmtId(tbinfo->attnames[adnum - 1]));
13768
13769         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13770                                  tbinfo->attnames[adnum - 1],
13771                                  tbinfo->dobj.namespace->dobj.name,
13772                                  NULL,
13773                                  tbinfo->rolname,
13774                                  false, "DEFAULT", SECTION_PRE_DATA,
13775                                  q->data, delq->data, NULL,
13776                                  NULL, 0,
13777                                  NULL, NULL);
13778
13779         destroyPQExpBuffer(q);
13780         destroyPQExpBuffer(delq);
13781 }
13782
13783 /*
13784  * getAttrName: extract the correct name for an attribute
13785  *
13786  * The array tblInfo->attnames[] only provides names of user attributes;
13787  * if a system attribute number is supplied, we have to fake it.
13788  * We also do a little bit of bounds checking for safety's sake.
13789  */
13790 static const char *
13791 getAttrName(int attrnum, TableInfo *tblInfo)
13792 {
13793         if (attrnum > 0 && attrnum <= tblInfo->numatts)
13794                 return tblInfo->attnames[attrnum - 1];
13795         switch (attrnum)
13796         {
13797                 case SelfItemPointerAttributeNumber:
13798                         return "ctid";
13799                 case ObjectIdAttributeNumber:
13800                         return "oid";
13801                 case MinTransactionIdAttributeNumber:
13802                         return "xmin";
13803                 case MinCommandIdAttributeNumber:
13804                         return "cmin";
13805                 case MaxTransactionIdAttributeNumber:
13806                         return "xmax";
13807                 case MaxCommandIdAttributeNumber:
13808                         return "cmax";
13809                 case TableOidAttributeNumber:
13810                         return "tableoid";
13811         }
13812         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13813                                   attrnum, tblInfo->dobj.name);
13814         return NULL;                            /* keep compiler quiet */
13815 }
13816
13817 /*
13818  * dumpIndex
13819  *        write out to fout a user-defined index
13820  */
13821 static void
13822 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13823 {
13824         TableInfo  *tbinfo = indxinfo->indextable;
13825         bool            is_constraint = (indxinfo->indexconstraint != 0);
13826         PQExpBuffer q;
13827         PQExpBuffer delq;
13828         PQExpBuffer labelq;
13829
13830         if (dataOnly)
13831                 return;
13832
13833         q = createPQExpBuffer();
13834         delq = createPQExpBuffer();
13835         labelq = createPQExpBuffer();
13836
13837         appendPQExpBuffer(labelq, "INDEX %s",
13838                                           fmtId(indxinfo->dobj.name));
13839
13840         /*
13841          * If there's an associated constraint, don't dump the index per se, but
13842          * do dump any comment for it.  (This is safe because dependency ordering
13843          * will have ensured the constraint is emitted first.)  Note that the
13844          * emitted comment has to be shown as depending on the constraint, not the
13845          * index, in such cases.
13846          */
13847         if (!is_constraint)
13848         {
13849                 if (binary_upgrade)
13850                         binary_upgrade_set_pg_class_oids(fout, q,
13851                                                                                          indxinfo->dobj.catId.oid, true);
13852
13853                 /* Plain secondary index */
13854                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13855
13856                 /* If the index is clustered, we need to record that. */
13857                 if (indxinfo->indisclustered)
13858                 {
13859                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13860                                                           fmtId(tbinfo->dobj.name));
13861                         appendPQExpBuffer(q, " ON %s;\n",
13862                                                           fmtId(indxinfo->dobj.name));
13863                 }
13864
13865                 /* If the index defines identity, we need to record that. */
13866                 if (indxinfo->indisreplident)
13867                 {
13868                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
13869                                                           fmtId(tbinfo->dobj.name));
13870                         appendPQExpBuffer(q, " INDEX %s;\n",
13871                                                           fmtId(indxinfo->dobj.name));
13872                 }
13873
13874                 /*
13875                  * DROP must be fully qualified in case same name appears in
13876                  * pg_catalog
13877                  */
13878                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13879                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13880                 appendPQExpBuffer(delq, "%s;\n",
13881                                                   fmtId(indxinfo->dobj.name));
13882
13883                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13884                                          indxinfo->dobj.name,
13885                                          tbinfo->dobj.namespace->dobj.name,
13886                                          indxinfo->tablespace,
13887                                          tbinfo->rolname, false,
13888                                          "INDEX", SECTION_POST_DATA,
13889                                          q->data, delq->data, NULL,
13890                                          NULL, 0,
13891                                          NULL, NULL);
13892         }
13893
13894         /* Dump Index Comments */
13895         dumpComment(fout, labelq->data,
13896                                 tbinfo->dobj.namespace->dobj.name,
13897                                 tbinfo->rolname,
13898                                 indxinfo->dobj.catId, 0,
13899                                 is_constraint ? indxinfo->indexconstraint :
13900                                 indxinfo->dobj.dumpId);
13901
13902         destroyPQExpBuffer(q);
13903         destroyPQExpBuffer(delq);
13904         destroyPQExpBuffer(labelq);
13905 }
13906
13907 /*
13908  * dumpConstraint
13909  *        write out to fout a user-defined constraint
13910  */
13911 static void
13912 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13913 {
13914         TableInfo  *tbinfo = coninfo->contable;
13915         PQExpBuffer q;
13916         PQExpBuffer delq;
13917
13918         /* Skip if not to be dumped */
13919         if (!coninfo->dobj.dump || dataOnly)
13920                 return;
13921
13922         q = createPQExpBuffer();
13923         delq = createPQExpBuffer();
13924
13925         if (coninfo->contype == 'p' ||
13926                 coninfo->contype == 'u' ||
13927                 coninfo->contype == 'x')
13928         {
13929                 /* Index-related constraint */
13930                 IndxInfo   *indxinfo;
13931                 int                     k;
13932
13933                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13934
13935                 if (indxinfo == NULL)
13936                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13937                                                   coninfo->dobj.name);
13938
13939                 if (binary_upgrade)
13940                         binary_upgrade_set_pg_class_oids(fout, q,
13941                                                                                          indxinfo->dobj.catId.oid, true);
13942
13943                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13944                                                   fmtId(tbinfo->dobj.name));
13945                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13946                                                   fmtId(coninfo->dobj.name));
13947
13948                 if (coninfo->condef)
13949                 {
13950                         /* pg_get_constraintdef should have provided everything */
13951                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13952                 }
13953                 else
13954                 {
13955                         appendPQExpBuffer(q, "%s (",
13956                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13957                         for (k = 0; k < indxinfo->indnkeys; k++)
13958                         {
13959                                 int                     indkey = (int) indxinfo->indkeys[k];
13960                                 const char *attname;
13961
13962                                 if (indkey == InvalidAttrNumber)
13963                                         break;
13964                                 attname = getAttrName(indkey, tbinfo);
13965
13966                                 appendPQExpBuffer(q, "%s%s",
13967                                                                   (k == 0) ? "" : ", ",
13968                                                                   fmtId(attname));
13969                         }
13970
13971                         appendPQExpBufferChar(q, ')');
13972
13973                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13974                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13975
13976                         if (coninfo->condeferrable)
13977                         {
13978                                 appendPQExpBufferStr(q, " DEFERRABLE");
13979                                 if (coninfo->condeferred)
13980                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
13981                         }
13982
13983                         appendPQExpBufferStr(q, ";\n");
13984                 }
13985
13986                 /* If the index is clustered, we need to record that. */
13987                 if (indxinfo->indisclustered)
13988                 {
13989                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13990                                                           fmtId(tbinfo->dobj.name));
13991                         appendPQExpBuffer(q, " ON %s;\n",
13992                                                           fmtId(indxinfo->dobj.name));
13993                 }
13994
13995                 /*
13996                  * DROP must be fully qualified in case same name appears in
13997                  * pg_catalog
13998                  */
13999                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
14000                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
14001                 appendPQExpBuffer(delq, "%s ",
14002                                                   fmtId(tbinfo->dobj.name));
14003                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14004                                                   fmtId(coninfo->dobj.name));
14005
14006                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14007                                          coninfo->dobj.name,
14008                                          tbinfo->dobj.namespace->dobj.name,
14009                                          indxinfo->tablespace,
14010                                          tbinfo->rolname, false,
14011                                          "CONSTRAINT", SECTION_POST_DATA,
14012                                          q->data, delq->data, NULL,
14013                                          NULL, 0,
14014                                          NULL, NULL);
14015         }
14016         else if (coninfo->contype == 'f')
14017         {
14018                 /*
14019                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
14020                  * current table data is not processed
14021                  */
14022                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
14023                                                   fmtId(tbinfo->dobj.name));
14024                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14025                                                   fmtId(coninfo->dobj.name),
14026                                                   coninfo->condef);
14027
14028                 /*
14029                  * DROP must be fully qualified in case same name appears in
14030                  * pg_catalog
14031                  */
14032                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
14033                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
14034                 appendPQExpBuffer(delq, "%s ",
14035                                                   fmtId(tbinfo->dobj.name));
14036                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14037                                                   fmtId(coninfo->dobj.name));
14038
14039                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14040                                          coninfo->dobj.name,
14041                                          tbinfo->dobj.namespace->dobj.name,
14042                                          NULL,
14043                                          tbinfo->rolname, false,
14044                                          "FK CONSTRAINT", SECTION_POST_DATA,
14045                                          q->data, delq->data, NULL,
14046                                          NULL, 0,
14047                                          NULL, NULL);
14048         }
14049         else if (coninfo->contype == 'c' && tbinfo)
14050         {
14051                 /* CHECK constraint on a table */
14052
14053                 /* Ignore if not to be dumped separately */
14054                 if (coninfo->separate)
14055                 {
14056                         /* not ONLY since we want it to propagate to children */
14057                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
14058                                                           fmtId(tbinfo->dobj.name));
14059                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14060                                                           fmtId(coninfo->dobj.name),
14061                                                           coninfo->condef);
14062
14063                         /*
14064                          * DROP must be fully qualified in case same name appears in
14065                          * pg_catalog
14066                          */
14067                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
14068                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14069                         appendPQExpBuffer(delq, "%s ",
14070                                                           fmtId(tbinfo->dobj.name));
14071                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14072                                                           fmtId(coninfo->dobj.name));
14073
14074                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14075                                                  coninfo->dobj.name,
14076                                                  tbinfo->dobj.namespace->dobj.name,
14077                                                  NULL,
14078                                                  tbinfo->rolname, false,
14079                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
14080                                                  q->data, delq->data, NULL,
14081                                                  NULL, 0,
14082                                                  NULL, NULL);
14083                 }
14084         }
14085         else if (coninfo->contype == 'c' && tbinfo == NULL)
14086         {
14087                 /* CHECK constraint on a domain */
14088                 TypeInfo   *tyinfo = coninfo->condomain;
14089
14090                 /* Ignore if not to be dumped separately */
14091                 if (coninfo->separate)
14092                 {
14093                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
14094                                                           fmtId(tyinfo->dobj.name));
14095                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14096                                                           fmtId(coninfo->dobj.name),
14097                                                           coninfo->condef);
14098
14099                         /*
14100                          * DROP must be fully qualified in case same name appears in
14101                          * pg_catalog
14102                          */
14103                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
14104                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
14105                         appendPQExpBuffer(delq, "%s ",
14106                                                           fmtId(tyinfo->dobj.name));
14107                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14108                                                           fmtId(coninfo->dobj.name));
14109
14110                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14111                                                  coninfo->dobj.name,
14112                                                  tyinfo->dobj.namespace->dobj.name,
14113                                                  NULL,
14114                                                  tyinfo->rolname, false,
14115                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
14116                                                  q->data, delq->data, NULL,
14117                                                  NULL, 0,
14118                                                  NULL, NULL);
14119                 }
14120         }
14121         else
14122         {
14123                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
14124                                           coninfo->contype);
14125         }
14126
14127         /* Dump Constraint Comments --- only works for table constraints */
14128         if (tbinfo && coninfo->separate)
14129                 dumpTableConstraintComment(fout, coninfo);
14130
14131         destroyPQExpBuffer(q);
14132         destroyPQExpBuffer(delq);
14133 }
14134
14135 /*
14136  * dumpTableConstraintComment --- dump a constraint's comment if any
14137  *
14138  * This is split out because we need the function in two different places
14139  * depending on whether the constraint is dumped as part of CREATE TABLE
14140  * or as a separate ALTER command.
14141  */
14142 static void
14143 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
14144 {
14145         TableInfo  *tbinfo = coninfo->contable;
14146         PQExpBuffer labelq = createPQExpBuffer();
14147
14148         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
14149                                           fmtId(coninfo->dobj.name));
14150         appendPQExpBuffer(labelq, "ON %s",
14151                                           fmtId(tbinfo->dobj.name));
14152         dumpComment(fout, labelq->data,
14153                                 tbinfo->dobj.namespace->dobj.name,
14154                                 tbinfo->rolname,
14155                                 coninfo->dobj.catId, 0,
14156                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
14157
14158         destroyPQExpBuffer(labelq);
14159 }
14160
14161 /*
14162  * findLastBuiltInOid -
14163  * find the last built in oid
14164  *
14165  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
14166  * pg_database entry for the current database
14167  */
14168 static Oid
14169 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
14170 {
14171         PGresult   *res;
14172         Oid                     last_oid;
14173         PQExpBuffer query = createPQExpBuffer();
14174
14175         resetPQExpBuffer(query);
14176         appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
14177         appendStringLiteralAH(query, dbname, fout);
14178
14179         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14180         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
14181         PQclear(res);
14182         destroyPQExpBuffer(query);
14183         return last_oid;
14184 }
14185
14186 /*
14187  * findLastBuiltInOid -
14188  * find the last built in oid
14189  *
14190  * For 7.0, we do this by assuming that the last thing that initdb does is to
14191  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
14192  * initdb won't be changing anymore, it'll do.
14193  */
14194 static Oid
14195 findLastBuiltinOid_V70(Archive *fout)
14196 {
14197         PGresult   *res;
14198         int                     last_oid;
14199
14200         res = ExecuteSqlQueryForSingleRow(fout,
14201                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
14202         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
14203         PQclear(res);
14204         return last_oid;
14205 }
14206
14207 /*
14208  * dumpSequence
14209  *        write the declaration (not data) of one user-defined sequence
14210  */
14211 static void
14212 dumpSequence(Archive *fout, TableInfo *tbinfo)
14213 {
14214         PGresult   *res;
14215         char       *startv,
14216                            *incby,
14217                            *maxv = NULL,
14218                            *minv = NULL,
14219                            *cache;
14220         char            bufm[100],
14221                                 bufx[100];
14222         bool            cycled;
14223         PQExpBuffer query = createPQExpBuffer();
14224         PQExpBuffer delqry = createPQExpBuffer();
14225         PQExpBuffer labelq = createPQExpBuffer();
14226
14227         /* Make sure we are in proper schema */
14228         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14229
14230         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
14231         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
14232
14233         if (fout->remoteVersion >= 80400)
14234         {
14235                 appendPQExpBuffer(query,
14236                                                   "SELECT sequence_name, "
14237                                                   "start_value, increment_by, "
14238                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14239                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14240                                                   "     ELSE max_value "
14241                                                   "END AS max_value, "
14242                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14243                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14244                                                   "     ELSE min_value "
14245                                                   "END AS min_value, "
14246                                                   "cache_value, is_cycled FROM %s",
14247                                                   bufx, bufm,
14248                                                   fmtId(tbinfo->dobj.name));
14249         }
14250         else
14251         {
14252                 appendPQExpBuffer(query,
14253                                                   "SELECT sequence_name, "
14254                                                   "0 AS start_value, increment_by, "
14255                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14256                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14257                                                   "     ELSE max_value "
14258                                                   "END AS max_value, "
14259                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14260                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14261                                                   "     ELSE min_value "
14262                                                   "END AS min_value, "
14263                                                   "cache_value, is_cycled FROM %s",
14264                                                   bufx, bufm,
14265                                                   fmtId(tbinfo->dobj.name));
14266         }
14267
14268         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14269
14270         if (PQntuples(res) != 1)
14271         {
14272                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14273                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14274                                                                  PQntuples(res)),
14275                                   tbinfo->dobj.name, PQntuples(res));
14276                 exit_nicely(1);
14277         }
14278
14279         /* Disable this check: it fails if sequence has been renamed */
14280 #ifdef NOT_USED
14281         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
14282         {
14283                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
14284                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
14285                 exit_nicely(1);
14286         }
14287 #endif
14288
14289         startv = PQgetvalue(res, 0, 1);
14290         incby = PQgetvalue(res, 0, 2);
14291         if (!PQgetisnull(res, 0, 3))
14292                 maxv = PQgetvalue(res, 0, 3);
14293         if (!PQgetisnull(res, 0, 4))
14294                 minv = PQgetvalue(res, 0, 4);
14295         cache = PQgetvalue(res, 0, 5);
14296         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
14297
14298         /*
14299          * DROP must be fully qualified in case same name appears in pg_catalog
14300          */
14301         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
14302                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14303         appendPQExpBuffer(delqry, "%s;\n",
14304                                           fmtId(tbinfo->dobj.name));
14305
14306         resetPQExpBuffer(query);
14307
14308         if (binary_upgrade)
14309         {
14310                 binary_upgrade_set_pg_class_oids(fout, query,
14311                                                                                  tbinfo->dobj.catId.oid, false);
14312                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
14313                                                                                                 tbinfo->dobj.catId.oid);
14314         }
14315
14316         appendPQExpBuffer(query,
14317                                           "CREATE SEQUENCE %s\n",
14318                                           fmtId(tbinfo->dobj.name));
14319
14320         if (fout->remoteVersion >= 80400)
14321                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
14322
14323         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
14324
14325         if (minv)
14326                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
14327         else
14328                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
14329
14330         if (maxv)
14331                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
14332         else
14333                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
14334
14335         appendPQExpBuffer(query,
14336                                           "    CACHE %s%s",
14337                                           cache, (cycled ? "\n    CYCLE" : ""));
14338
14339         appendPQExpBufferStr(query, ";\n");
14340
14341         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
14342
14343         /* binary_upgrade:      no need to clear TOAST table oid */
14344
14345         if (binary_upgrade)
14346                 binary_upgrade_extension_member(query, &tbinfo->dobj,
14347                                                                                 labelq->data);
14348
14349         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14350                                  tbinfo->dobj.name,
14351                                  tbinfo->dobj.namespace->dobj.name,
14352                                  NULL,
14353                                  tbinfo->rolname,
14354                                  false, "SEQUENCE", SECTION_PRE_DATA,
14355                                  query->data, delqry->data, NULL,
14356                                  NULL, 0,
14357                                  NULL, NULL);
14358
14359         /*
14360          * If the sequence is owned by a table column, emit the ALTER for it as a
14361          * separate TOC entry immediately following the sequence's own entry. It's
14362          * OK to do this rather than using full sorting logic, because the
14363          * dependency that tells us it's owned will have forced the table to be
14364          * created first.  We can't just include the ALTER in the TOC entry
14365          * because it will fail if we haven't reassigned the sequence owner to
14366          * match the table's owner.
14367          *
14368          * We need not schema-qualify the table reference because both sequence
14369          * and table must be in the same schema.
14370          */
14371         if (OidIsValid(tbinfo->owning_tab))
14372         {
14373                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14374
14375                 if (owning_tab && owning_tab->dobj.dump)
14376                 {
14377                         resetPQExpBuffer(query);
14378                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14379                                                           fmtId(tbinfo->dobj.name));
14380                         appendPQExpBuffer(query, " OWNED BY %s",
14381                                                           fmtId(owning_tab->dobj.name));
14382                         appendPQExpBuffer(query, ".%s;\n",
14383                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14384
14385                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14386                                                  tbinfo->dobj.name,
14387                                                  tbinfo->dobj.namespace->dobj.name,
14388                                                  NULL,
14389                                                  tbinfo->rolname,
14390                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14391                                                  query->data, "", NULL,
14392                                                  &(tbinfo->dobj.dumpId), 1,
14393                                                  NULL, NULL);
14394                 }
14395         }
14396
14397         /* Dump Sequence Comments and Security Labels */
14398         dumpComment(fout, labelq->data,
14399                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14400                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14401         dumpSecLabel(fout, labelq->data,
14402                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14403                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14404
14405         PQclear(res);
14406
14407         destroyPQExpBuffer(query);
14408         destroyPQExpBuffer(delqry);
14409         destroyPQExpBuffer(labelq);
14410 }
14411
14412 /*
14413  * dumpSequenceData
14414  *        write the data of one user-defined sequence
14415  */
14416 static void
14417 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14418 {
14419         TableInfo  *tbinfo = tdinfo->tdtable;
14420         PGresult   *res;
14421         char       *last;
14422         bool            called;
14423         PQExpBuffer query = createPQExpBuffer();
14424
14425         /* Make sure we are in proper schema */
14426         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14427
14428         appendPQExpBuffer(query,
14429                                           "SELECT last_value, is_called FROM %s",
14430                                           fmtId(tbinfo->dobj.name));
14431
14432         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14433
14434         if (PQntuples(res) != 1)
14435         {
14436                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14437                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14438                                                                  PQntuples(res)),
14439                                   tbinfo->dobj.name, PQntuples(res));
14440                 exit_nicely(1);
14441         }
14442
14443         last = PQgetvalue(res, 0, 0);
14444         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14445
14446         resetPQExpBuffer(query);
14447         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
14448         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14449         appendPQExpBuffer(query, ", %s, %s);\n",
14450                                           last, (called ? "true" : "false"));
14451
14452         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14453                                  tbinfo->dobj.name,
14454                                  tbinfo->dobj.namespace->dobj.name,
14455                                  NULL,
14456                                  tbinfo->rolname,
14457                                  false, "SEQUENCE SET", SECTION_DATA,
14458                                  query->data, "", NULL,
14459                                  &(tbinfo->dobj.dumpId), 1,
14460                                  NULL, NULL);
14461
14462         PQclear(res);
14463
14464         destroyPQExpBuffer(query);
14465 }
14466
14467 /*
14468  * dumpTrigger
14469  *        write the declaration of one user-defined table trigger
14470  */
14471 static void
14472 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14473 {
14474         TableInfo  *tbinfo = tginfo->tgtable;
14475         PQExpBuffer query;
14476         PQExpBuffer delqry;
14477         PQExpBuffer labelq;
14478         char       *tgargs;
14479         size_t          lentgargs;
14480         const char *p;
14481         int                     findx;
14482
14483         /*
14484          * we needn't check dobj.dump because TriggerInfo wouldn't have been
14485          * created in the first place for non-dumpable triggers
14486          */
14487         if (dataOnly)
14488                 return;
14489
14490         query = createPQExpBuffer();
14491         delqry = createPQExpBuffer();
14492         labelq = createPQExpBuffer();
14493
14494         /*
14495          * DROP must be fully qualified in case same name appears in pg_catalog
14496          */
14497         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14498                                           fmtId(tginfo->dobj.name));
14499         appendPQExpBuffer(delqry, "ON %s.",
14500                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14501         appendPQExpBuffer(delqry, "%s;\n",
14502                                           fmtId(tbinfo->dobj.name));
14503
14504         if (tginfo->tgdef)
14505         {
14506                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14507         }
14508         else
14509         {
14510                 if (tginfo->tgisconstraint)
14511                 {
14512                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
14513                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14514                 }
14515                 else
14516                 {
14517                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
14518                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14519                 }
14520                 appendPQExpBufferStr(query, "\n    ");
14521
14522                 /* Trigger type */
14523                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14524                         appendPQExpBufferStr(query, "BEFORE");
14525                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14526                         appendPQExpBufferStr(query, "AFTER");
14527                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14528                         appendPQExpBufferStr(query, "INSTEAD OF");
14529                 else
14530                 {
14531                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14532                         exit_nicely(1);
14533                 }
14534
14535                 findx = 0;
14536                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14537                 {
14538                         appendPQExpBufferStr(query, " INSERT");
14539                         findx++;
14540                 }
14541                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14542                 {
14543                         if (findx > 0)
14544                                 appendPQExpBufferStr(query, " OR DELETE");
14545                         else
14546                                 appendPQExpBufferStr(query, " DELETE");
14547                         findx++;
14548                 }
14549                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14550                 {
14551                         if (findx > 0)
14552                                 appendPQExpBufferStr(query, " OR UPDATE");
14553                         else
14554                                 appendPQExpBufferStr(query, " UPDATE");
14555                         findx++;
14556                 }
14557                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14558                 {
14559                         if (findx > 0)
14560                                 appendPQExpBufferStr(query, " OR TRUNCATE");
14561                         else
14562                                 appendPQExpBufferStr(query, " TRUNCATE");
14563                         findx++;
14564                 }
14565                 appendPQExpBuffer(query, " ON %s\n",
14566                                                   fmtId(tbinfo->dobj.name));
14567
14568                 if (tginfo->tgisconstraint)
14569                 {
14570                         if (OidIsValid(tginfo->tgconstrrelid))
14571                         {
14572                                 /* If we are using regclass, name is already quoted */
14573                                 if (fout->remoteVersion >= 70300)
14574                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14575                                                                           tginfo->tgconstrrelname);
14576                                 else
14577                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14578                                                                           fmtId(tginfo->tgconstrrelname));
14579                         }
14580                         if (!tginfo->tgdeferrable)
14581                                 appendPQExpBufferStr(query, "NOT ");
14582                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
14583                         if (tginfo->tginitdeferred)
14584                                 appendPQExpBufferStr(query, "DEFERRED\n");
14585                         else
14586                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
14587                 }
14588
14589                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14590                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
14591                 else
14592                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
14593
14594                 /* In 7.3, result of regproc is already quoted */
14595                 if (fout->remoteVersion >= 70300)
14596                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14597                                                           tginfo->tgfname);
14598                 else
14599                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14600                                                           fmtId(tginfo->tgfname));
14601
14602                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14603                                                                                   &lentgargs);
14604                 p = tgargs;
14605                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14606                 {
14607                         /* find the embedded null that terminates this trigger argument */
14608                         size_t          tlen = strlen(p);
14609
14610                         if (p + tlen >= tgargs + lentgargs)
14611                         {
14612                                 /* hm, not found before end of bytea value... */
14613                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14614                                                   tginfo->tgargs,
14615                                                   tginfo->dobj.name,
14616                                                   tbinfo->dobj.name);
14617                                 exit_nicely(1);
14618                         }
14619
14620                         if (findx > 0)
14621                                 appendPQExpBufferStr(query, ", ");
14622                         appendStringLiteralAH(query, p, fout);
14623                         p += tlen + 1;
14624                 }
14625                 free(tgargs);
14626                 appendPQExpBufferStr(query, ");\n");
14627         }
14628
14629         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14630         {
14631                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
14632                                                   fmtId(tbinfo->dobj.name));
14633                 switch (tginfo->tgenabled)
14634                 {
14635                         case 'D':
14636                         case 'f':
14637                                 appendPQExpBufferStr(query, "DISABLE");
14638                                 break;
14639                         case 'A':
14640                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
14641                                 break;
14642                         case 'R':
14643                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
14644                                 break;
14645                         default:
14646                                 appendPQExpBufferStr(query, "ENABLE");
14647                                 break;
14648                 }
14649                 appendPQExpBuffer(query, " TRIGGER %s;\n",
14650                                                   fmtId(tginfo->dobj.name));
14651         }
14652
14653         appendPQExpBuffer(labelq, "TRIGGER %s ",
14654                                           fmtId(tginfo->dobj.name));
14655         appendPQExpBuffer(labelq, "ON %s",
14656                                           fmtId(tbinfo->dobj.name));
14657
14658         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14659                                  tginfo->dobj.name,
14660                                  tbinfo->dobj.namespace->dobj.name,
14661                                  NULL,
14662                                  tbinfo->rolname, false,
14663                                  "TRIGGER", SECTION_POST_DATA,
14664                                  query->data, delqry->data, NULL,
14665                                  NULL, 0,
14666                                  NULL, NULL);
14667
14668         dumpComment(fout, labelq->data,
14669                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14670                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14671
14672         destroyPQExpBuffer(query);
14673         destroyPQExpBuffer(delqry);
14674         destroyPQExpBuffer(labelq);
14675 }
14676
14677 /*
14678  * dumpEventTrigger
14679  *        write the declaration of one user-defined event trigger
14680  */
14681 static void
14682 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14683 {
14684         PQExpBuffer query;
14685         PQExpBuffer labelq;
14686
14687         /* Skip if not to be dumped */
14688         if (!evtinfo->dobj.dump || dataOnly)
14689                 return;
14690
14691         query = createPQExpBuffer();
14692         labelq = createPQExpBuffer();
14693
14694         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
14695         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14696         appendPQExpBufferStr(query, " ON ");
14697         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14698         appendPQExpBufferStr(query, " ");
14699
14700         if (strcmp("", evtinfo->evttags) != 0)
14701         {
14702                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14703                 appendPQExpBufferStr(query, evtinfo->evttags);
14704                 appendPQExpBufferStr(query, ") ");
14705         }
14706
14707         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
14708         appendPQExpBufferStr(query, evtinfo->evtfname);
14709         appendPQExpBufferStr(query, "();\n");
14710
14711         if (evtinfo->evtenabled != 'O')
14712         {
14713                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14714                                                   fmtId(evtinfo->dobj.name));
14715                 switch (evtinfo->evtenabled)
14716                 {
14717                         case 'D':
14718                                 appendPQExpBufferStr(query, "DISABLE");
14719                                 break;
14720                         case 'A':
14721                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
14722                                 break;
14723                         case 'R':
14724                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
14725                                 break;
14726                         default:
14727                                 appendPQExpBufferStr(query, "ENABLE");
14728                                 break;
14729                 }
14730                 appendPQExpBufferStr(query, ";\n");
14731         }
14732         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14733                                           fmtId(evtinfo->dobj.name));
14734
14735         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14736                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14737                                  "EVENT TRIGGER", SECTION_POST_DATA,
14738                                  query->data, "", NULL, NULL, 0, NULL, NULL);
14739
14740         dumpComment(fout, labelq->data,
14741                                 NULL, NULL,
14742                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14743
14744         destroyPQExpBuffer(query);
14745         destroyPQExpBuffer(labelq);
14746 }
14747
14748 /*
14749  * dumpRule
14750  *              Dump a rule
14751  */
14752 static void
14753 dumpRule(Archive *fout, RuleInfo *rinfo)
14754 {
14755         TableInfo  *tbinfo = rinfo->ruletable;
14756         PQExpBuffer query;
14757         PQExpBuffer cmd;
14758         PQExpBuffer delcmd;
14759         PQExpBuffer labelq;
14760         PGresult   *res;
14761
14762         /* Skip if not to be dumped */
14763         if (!rinfo->dobj.dump || dataOnly)
14764                 return;
14765
14766         /*
14767          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14768          * we do not want to dump it as a separate object.
14769          */
14770         if (!rinfo->separate)
14771                 return;
14772
14773         /*
14774          * Make sure we are in proper schema.
14775          */
14776         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14777
14778         query = createPQExpBuffer();
14779         cmd = createPQExpBuffer();
14780         delcmd = createPQExpBuffer();
14781         labelq = createPQExpBuffer();
14782
14783         if (fout->remoteVersion >= 70300)
14784         {
14785                 appendPQExpBuffer(query,
14786                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14787                                                   rinfo->dobj.catId.oid);
14788         }
14789         else
14790         {
14791                 /* Rule name was unique before 7.3 ... */
14792                 appendPQExpBuffer(query,
14793                                                   "SELECT pg_get_ruledef('%s') AS definition",
14794                                                   rinfo->dobj.name);
14795         }
14796
14797         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14798
14799         if (PQntuples(res) != 1)
14800         {
14801                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14802                                   rinfo->dobj.name, tbinfo->dobj.name);
14803                 exit_nicely(1);
14804         }
14805
14806         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14807
14808         /*
14809          * Add the command to alter the rules replication firing semantics if it
14810          * differs from the default.
14811          */
14812         if (rinfo->ev_enabled != 'O')
14813         {
14814                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14815                 switch (rinfo->ev_enabled)
14816                 {
14817                         case 'A':
14818                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14819                                                                   fmtId(rinfo->dobj.name));
14820                                 break;
14821                         case 'R':
14822                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14823                                                                   fmtId(rinfo->dobj.name));
14824                                 break;
14825                         case 'D':
14826                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14827                                                                   fmtId(rinfo->dobj.name));
14828                                 break;
14829                 }
14830         }
14831
14832         /*
14833          * Apply view's reloptions when its ON SELECT rule is separate.
14834          */
14835         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14836         {
14837                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14838                                                   fmtId(tbinfo->dobj.name),
14839                                                   rinfo->reloptions);
14840         }
14841
14842         /*
14843          * DROP must be fully qualified in case same name appears in pg_catalog
14844          */
14845         appendPQExpBuffer(delcmd, "DROP RULE %s ",
14846                                           fmtId(rinfo->dobj.name));
14847         appendPQExpBuffer(delcmd, "ON %s.",
14848                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14849         appendPQExpBuffer(delcmd, "%s;\n",
14850                                           fmtId(tbinfo->dobj.name));
14851
14852         appendPQExpBuffer(labelq, "RULE %s",
14853                                           fmtId(rinfo->dobj.name));
14854         appendPQExpBuffer(labelq, " ON %s",
14855                                           fmtId(tbinfo->dobj.name));
14856
14857         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14858                                  rinfo->dobj.name,
14859                                  tbinfo->dobj.namespace->dobj.name,
14860                                  NULL,
14861                                  tbinfo->rolname, false,
14862                                  "RULE", SECTION_POST_DATA,
14863                                  cmd->data, delcmd->data, NULL,
14864                                  NULL, 0,
14865                                  NULL, NULL);
14866
14867         /* Dump rule comments */
14868         dumpComment(fout, labelq->data,
14869                                 tbinfo->dobj.namespace->dobj.name,
14870                                 tbinfo->rolname,
14871                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14872
14873         PQclear(res);
14874
14875         destroyPQExpBuffer(query);
14876         destroyPQExpBuffer(cmd);
14877         destroyPQExpBuffer(delcmd);
14878         destroyPQExpBuffer(labelq);
14879 }
14880
14881 /*
14882  * getExtensionMembership --- obtain extension membership data
14883  */
14884 void
14885 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14886                                            int numExtensions)
14887 {
14888         PQExpBuffer query;
14889         PGresult   *res;
14890         int                     ntups,
14891                                 i;
14892         int                     i_classid,
14893                                 i_objid,
14894                                 i_refclassid,
14895                                 i_refobjid;
14896         DumpableObject *dobj,
14897                            *refdobj;
14898
14899         /* Nothing to do if no extensions */
14900         if (numExtensions == 0)
14901                 return;
14902
14903         /* Make sure we are in proper schema */
14904         selectSourceSchema(fout, "pg_catalog");
14905
14906         query = createPQExpBuffer();
14907
14908         /* refclassid constraint is redundant but may speed the search */
14909         appendPQExpBufferStr(query, "SELECT "
14910                                                  "classid, objid, refclassid, refobjid "
14911                                                  "FROM pg_depend "
14912                                                  "WHERE refclassid = 'pg_extension'::regclass "
14913                                                  "AND deptype = 'e' "
14914                                                  "ORDER BY 3,4");
14915
14916         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14917
14918         ntups = PQntuples(res);
14919
14920         i_classid = PQfnumber(res, "classid");
14921         i_objid = PQfnumber(res, "objid");
14922         i_refclassid = PQfnumber(res, "refclassid");
14923         i_refobjid = PQfnumber(res, "refobjid");
14924
14925         /*
14926          * Since we ordered the SELECT by referenced ID, we can expect that
14927          * multiple entries for the same extension will appear together; this
14928          * saves on searches.
14929          */
14930         refdobj = NULL;
14931
14932         for (i = 0; i < ntups; i++)
14933         {
14934                 CatalogId       objId;
14935                 CatalogId       refobjId;
14936
14937                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14938                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14939                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14940                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14941
14942                 if (refdobj == NULL ||
14943                         refdobj->catId.tableoid != refobjId.tableoid ||
14944                         refdobj->catId.oid != refobjId.oid)
14945                         refdobj = findObjectByCatalogId(refobjId);
14946
14947                 /*
14948                  * Failure to find objects mentioned in pg_depend is not unexpected,
14949                  * since for example we don't collect info about TOAST tables.
14950                  */
14951                 if (refdobj == NULL)
14952                 {
14953 #ifdef NOT_USED
14954                         fprintf(stderr, "no referenced object %u %u\n",
14955                                         refobjId.tableoid, refobjId.oid);
14956 #endif
14957                         continue;
14958                 }
14959
14960                 dobj = findObjectByCatalogId(objId);
14961
14962                 if (dobj == NULL)
14963                 {
14964 #ifdef NOT_USED
14965                         fprintf(stderr, "no referencing object %u %u\n",
14966                                         objId.tableoid, objId.oid);
14967 #endif
14968                         continue;
14969                 }
14970
14971                 /* Record dependency so that getDependencies needn't repeat this */
14972                 addObjectDependency(dobj, refdobj->dumpId);
14973
14974                 dobj->ext_member = true;
14975
14976                 /*
14977                  * Normally, mark the member object as not to be dumped.  But in
14978                  * binary upgrades, we still dump the members individually, since the
14979                  * idea is to exactly reproduce the database contents rather than
14980                  * replace the extension contents with something different.
14981                  */
14982                 if (!binary_upgrade)
14983                         dobj->dump = false;
14984                 else
14985                         dobj->dump = refdobj->dump;
14986         }
14987
14988         PQclear(res);
14989
14990         /*
14991          * Now identify extension configuration tables and create TableDataInfo
14992          * objects for them, ensuring their data will be dumped even though the
14993          * tables themselves won't be.
14994          *
14995          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14996          * user data in a configuration table is treated like schema data. This
14997          * seems appropriate since system data in a config table would get
14998          * reloaded by CREATE EXTENSION.
14999          */
15000         for (i = 0; i < numExtensions; i++)
15001         {
15002                 ExtensionInfo *curext = &(extinfo[i]);
15003                 char       *extconfig = curext->extconfig;
15004                 char       *extcondition = curext->extcondition;
15005                 char      **extconfigarray = NULL;
15006                 char      **extconditionarray = NULL;
15007                 int                     nconfigitems;
15008                 int                     nconditionitems;
15009
15010                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
15011                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
15012                         nconfigitems == nconditionitems)
15013                 {
15014                         int                     j;
15015
15016                         for (j = 0; j < nconfigitems; j++)
15017                         {
15018                                 TableInfo  *configtbl;
15019                                 Oid                     configtbloid = atooid(extconfigarray[j]);
15020                                 bool            dumpobj = curext->dobj.dump;
15021
15022                                 configtbl = findTableByOid(configtbloid);
15023                                 if (configtbl == NULL)
15024                                         continue;
15025
15026                                 /*
15027                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
15028                                  * unless the table or its schema is explicitly included
15029                                  */
15030                                 if (!curext->dobj.dump)
15031                                 {
15032                                         /* check table explicitly requested */
15033                                         if (table_include_oids.head != NULL &&
15034                                                 simple_oid_list_member(&table_include_oids,
15035                                                                                            configtbloid))
15036                                                 dumpobj = true;
15037
15038                                         /* check table's schema explicitly requested */
15039                                         if (configtbl->dobj.namespace->dobj.dump)
15040                                                 dumpobj = true;
15041                                 }
15042
15043                                 /* check table excluded by an exclusion switch */
15044                                 if (table_exclude_oids.head != NULL &&
15045                                         simple_oid_list_member(&table_exclude_oids,
15046                                                                                    configtbloid))
15047                                         dumpobj = false;
15048
15049                                 /* check schema excluded by an exclusion switch */
15050                                 if (simple_oid_list_member(&schema_exclude_oids,
15051                                                                   configtbl->dobj.namespace->dobj.catId.oid))
15052                                         dumpobj = false;
15053
15054                                 if (dumpobj)
15055                                 {
15056                                         /*
15057                                          * Note: config tables are dumped without OIDs regardless
15058                                          * of the --oids setting.  This is because row filtering
15059                                          * conditions aren't compatible with dumping OIDs.
15060                                          */
15061                                         makeTableDataInfo(configtbl, false);
15062                                         if (configtbl->dataObj != NULL)
15063                                         {
15064                                                 if (strlen(extconditionarray[j]) > 0)
15065                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
15066                                         }
15067                                 }
15068                         }
15069                 }
15070                 if (extconfigarray)
15071                         free(extconfigarray);
15072                 if (extconditionarray)
15073                         free(extconditionarray);
15074         }
15075
15076         destroyPQExpBuffer(query);
15077 }
15078
15079 /*
15080  * getDependencies --- obtain available dependency data
15081  */
15082 static void
15083 getDependencies(Archive *fout)
15084 {
15085         PQExpBuffer query;
15086         PGresult   *res;
15087         int                     ntups,
15088                                 i;
15089         int                     i_classid,
15090                                 i_objid,
15091                                 i_refclassid,
15092                                 i_refobjid,
15093                                 i_deptype;
15094         DumpableObject *dobj,
15095                            *refdobj;
15096
15097         /* No dependency info available before 7.3 */
15098         if (fout->remoteVersion < 70300)
15099                 return;
15100
15101         if (g_verbose)
15102                 write_msg(NULL, "reading dependency data\n");
15103
15104         /* Make sure we are in proper schema */
15105         selectSourceSchema(fout, "pg_catalog");
15106
15107         query = createPQExpBuffer();
15108
15109         /*
15110          * PIN dependencies aren't interesting, and EXTENSION dependencies were
15111          * already processed by getExtensionMembership.
15112          */
15113         appendPQExpBufferStr(query, "SELECT "
15114                                                  "classid, objid, refclassid, refobjid, deptype "
15115                                                  "FROM pg_depend "
15116                                                  "WHERE deptype != 'p' AND deptype != 'e' "
15117                                                  "ORDER BY 1,2");
15118
15119         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15120
15121         ntups = PQntuples(res);
15122
15123         i_classid = PQfnumber(res, "classid");
15124         i_objid = PQfnumber(res, "objid");
15125         i_refclassid = PQfnumber(res, "refclassid");
15126         i_refobjid = PQfnumber(res, "refobjid");
15127         i_deptype = PQfnumber(res, "deptype");
15128
15129         /*
15130          * Since we ordered the SELECT by referencing ID, we can expect that
15131          * multiple entries for the same object will appear together; this saves
15132          * on searches.
15133          */
15134         dobj = NULL;
15135
15136         for (i = 0; i < ntups; i++)
15137         {
15138                 CatalogId       objId;
15139                 CatalogId       refobjId;
15140                 char            deptype;
15141
15142                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
15143                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
15144                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
15145                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
15146                 deptype = *(PQgetvalue(res, i, i_deptype));
15147
15148                 if (dobj == NULL ||
15149                         dobj->catId.tableoid != objId.tableoid ||
15150                         dobj->catId.oid != objId.oid)
15151                         dobj = findObjectByCatalogId(objId);
15152
15153                 /*
15154                  * Failure to find objects mentioned in pg_depend is not unexpected,
15155                  * since for example we don't collect info about TOAST tables.
15156                  */
15157                 if (dobj == NULL)
15158                 {
15159 #ifdef NOT_USED
15160                         fprintf(stderr, "no referencing object %u %u\n",
15161                                         objId.tableoid, objId.oid);
15162 #endif
15163                         continue;
15164                 }
15165
15166                 refdobj = findObjectByCatalogId(refobjId);
15167
15168                 if (refdobj == NULL)
15169                 {
15170 #ifdef NOT_USED
15171                         fprintf(stderr, "no referenced object %u %u\n",
15172                                         refobjId.tableoid, refobjId.oid);
15173 #endif
15174                         continue;
15175                 }
15176
15177                 /*
15178                  * Ordinarily, table rowtypes have implicit dependencies on their
15179                  * tables.  However, for a composite type the implicit dependency goes
15180                  * the other way in pg_depend; which is the right thing for DROP but
15181                  * it doesn't produce the dependency ordering we need. So in that one
15182                  * case, we reverse the direction of the dependency.
15183                  */
15184                 if (deptype == 'i' &&
15185                         dobj->objType == DO_TABLE &&
15186                         refdobj->objType == DO_TYPE)
15187                         addObjectDependency(refdobj, dobj->dumpId);
15188                 else
15189                         /* normal case */
15190                         addObjectDependency(dobj, refdobj->dumpId);
15191         }
15192
15193         PQclear(res);
15194
15195         destroyPQExpBuffer(query);
15196 }
15197
15198
15199 /*
15200  * createBoundaryObjects - create dummy DumpableObjects to represent
15201  * dump section boundaries.
15202  */
15203 static DumpableObject *
15204 createBoundaryObjects(void)
15205 {
15206         DumpableObject *dobjs;
15207
15208         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
15209
15210         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
15211         dobjs[0].catId = nilCatalogId;
15212         AssignDumpId(dobjs + 0);
15213         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
15214
15215         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
15216         dobjs[1].catId = nilCatalogId;
15217         AssignDumpId(dobjs + 1);
15218         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
15219
15220         return dobjs;
15221 }
15222
15223 /*
15224  * addBoundaryDependencies - add dependencies as needed to enforce the dump
15225  * section boundaries.
15226  */
15227 static void
15228 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
15229                                                 DumpableObject *boundaryObjs)
15230 {
15231         DumpableObject *preDataBound = boundaryObjs + 0;
15232         DumpableObject *postDataBound = boundaryObjs + 1;
15233         int                     i;
15234
15235         for (i = 0; i < numObjs; i++)
15236         {
15237                 DumpableObject *dobj = dobjs[i];
15238
15239                 /*
15240                  * The classification of object types here must match the SECTION_xxx
15241                  * values assigned during subsequent ArchiveEntry calls!
15242                  */
15243                 switch (dobj->objType)
15244                 {
15245                         case DO_NAMESPACE:
15246                         case DO_EXTENSION:
15247                         case DO_TYPE:
15248                         case DO_SHELL_TYPE:
15249                         case DO_FUNC:
15250                         case DO_AGG:
15251                         case DO_OPERATOR:
15252                         case DO_OPCLASS:
15253                         case DO_OPFAMILY:
15254                         case DO_COLLATION:
15255                         case DO_CONVERSION:
15256                         case DO_TABLE:
15257                         case DO_ATTRDEF:
15258                         case DO_PROCLANG:
15259                         case DO_CAST:
15260                         case DO_DUMMY_TYPE:
15261                         case DO_TSPARSER:
15262                         case DO_TSDICT:
15263                         case DO_TSTEMPLATE:
15264                         case DO_TSCONFIG:
15265                         case DO_FDW:
15266                         case DO_FOREIGN_SERVER:
15267                         case DO_BLOB:
15268                                 /* Pre-data objects: must come before the pre-data boundary */
15269                                 addObjectDependency(preDataBound, dobj->dumpId);
15270                                 break;
15271                         case DO_TABLE_DATA:
15272                         case DO_BLOB_DATA:
15273                                 /* Data objects: must come between the boundaries */
15274                                 addObjectDependency(dobj, preDataBound->dumpId);
15275                                 addObjectDependency(postDataBound, dobj->dumpId);
15276                                 break;
15277                         case DO_INDEX:
15278                         case DO_REFRESH_MATVIEW:
15279                         case DO_TRIGGER:
15280                         case DO_EVENT_TRIGGER:
15281                         case DO_DEFAULT_ACL:
15282                                 /* Post-data objects: must come after the post-data boundary */
15283                                 addObjectDependency(dobj, postDataBound->dumpId);
15284                                 break;
15285                         case DO_RULE:
15286                                 /* Rules are post-data, but only if dumped separately */
15287                                 if (((RuleInfo *) dobj)->separate)
15288                                         addObjectDependency(dobj, postDataBound->dumpId);
15289                                 break;
15290                         case DO_CONSTRAINT:
15291                         case DO_FK_CONSTRAINT:
15292                                 /* Constraints are post-data, but only if dumped separately */
15293                                 if (((ConstraintInfo *) dobj)->separate)
15294                                         addObjectDependency(dobj, postDataBound->dumpId);
15295                                 break;
15296                         case DO_PRE_DATA_BOUNDARY:
15297                                 /* nothing to do */
15298                                 break;
15299                         case DO_POST_DATA_BOUNDARY:
15300                                 /* must come after the pre-data boundary */
15301                                 addObjectDependency(dobj, preDataBound->dumpId);
15302                                 break;
15303                 }
15304         }
15305 }
15306
15307
15308 /*
15309  * BuildArchiveDependencies - create dependency data for archive TOC entries
15310  *
15311  * The raw dependency data obtained by getDependencies() is not terribly
15312  * useful in an archive dump, because in many cases there are dependency
15313  * chains linking through objects that don't appear explicitly in the dump.
15314  * For example, a view will depend on its _RETURN rule while the _RETURN rule
15315  * will depend on other objects --- but the rule will not appear as a separate
15316  * object in the dump.  We need to adjust the view's dependencies to include
15317  * whatever the rule depends on that is included in the dump.
15318  *
15319  * Just to make things more complicated, there are also "special" dependencies
15320  * such as the dependency of a TABLE DATA item on its TABLE, which we must
15321  * not rearrange because pg_restore knows that TABLE DATA only depends on
15322  * its table.  In these cases we must leave the dependencies strictly as-is
15323  * even if they refer to not-to-be-dumped objects.
15324  *
15325  * To handle this, the convention is that "special" dependencies are created
15326  * during ArchiveEntry calls, and an archive TOC item that has any such
15327  * entries will not be touched here.  Otherwise, we recursively search the
15328  * DumpableObject data structures to build the correct dependencies for each
15329  * archive TOC item.
15330  */
15331 static void
15332 BuildArchiveDependencies(Archive *fout)
15333 {
15334         ArchiveHandle *AH = (ArchiveHandle *) fout;
15335         TocEntry   *te;
15336
15337         /* Scan all TOC entries in the archive */
15338         for (te = AH->toc->next; te != AH->toc; te = te->next)
15339         {
15340                 DumpableObject *dobj;
15341                 DumpId     *dependencies;
15342                 int                     nDeps;
15343                 int                     allocDeps;
15344
15345                 /* No need to process entries that will not be dumped */
15346                 if (te->reqs == 0)
15347                         continue;
15348                 /* Ignore entries that already have "special" dependencies */
15349                 if (te->nDeps > 0)
15350                         continue;
15351                 /* Otherwise, look up the item's original DumpableObject, if any */
15352                 dobj = findObjectByDumpId(te->dumpId);
15353                 if (dobj == NULL)
15354                         continue;
15355                 /* No work if it has no dependencies */
15356                 if (dobj->nDeps <= 0)
15357                         continue;
15358                 /* Set up work array */
15359                 allocDeps = 64;
15360                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
15361                 nDeps = 0;
15362                 /* Recursively find all dumpable dependencies */
15363                 findDumpableDependencies(AH, dobj,
15364                                                                  &dependencies, &nDeps, &allocDeps);
15365                 /* And save 'em ... */
15366                 if (nDeps > 0)
15367                 {
15368                         dependencies = (DumpId *) pg_realloc(dependencies,
15369                                                                                                  nDeps * sizeof(DumpId));
15370                         te->dependencies = dependencies;
15371                         te->nDeps = nDeps;
15372                 }
15373                 else
15374                         free(dependencies);
15375         }
15376 }
15377
15378 /* Recursive search subroutine for BuildArchiveDependencies */
15379 static void
15380 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
15381                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
15382 {
15383         int                     i;
15384
15385         /*
15386          * Ignore section boundary objects: if we search through them, we'll
15387          * report lots of bogus dependencies.
15388          */
15389         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15390                 dobj->objType == DO_POST_DATA_BOUNDARY)
15391                 return;
15392
15393         for (i = 0; i < dobj->nDeps; i++)
15394         {
15395                 DumpId          depid = dobj->dependencies[i];
15396
15397                 if (TocIDRequired(AH, depid) != 0)
15398                 {
15399                         /* Object will be dumped, so just reference it as a dependency */
15400                         if (*nDeps >= *allocDeps)
15401                         {
15402                                 *allocDeps *= 2;
15403                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15404                                                                                                 *allocDeps * sizeof(DumpId));
15405                         }
15406                         (*dependencies)[*nDeps] = depid;
15407                         (*nDeps)++;
15408                 }
15409                 else
15410                 {
15411                         /*
15412                          * Object will not be dumped, so recursively consider its deps. We
15413                          * rely on the assumption that sortDumpableObjects already broke
15414                          * any dependency loops, else we might recurse infinitely.
15415                          */
15416                         DumpableObject *otherdobj = findObjectByDumpId(depid);
15417
15418                         if (otherdobj)
15419                                 findDumpableDependencies(AH, otherdobj,
15420                                                                                  dependencies, nDeps, allocDeps);
15421                 }
15422         }
15423 }
15424
15425
15426 /*
15427  * selectSourceSchema - make the specified schema the active search path
15428  * in the source database.
15429  *
15430  * NB: pg_catalog is explicitly searched after the specified schema;
15431  * so user names are only qualified if they are cross-schema references,
15432  * and system names are only qualified if they conflict with a user name
15433  * in the current schema.
15434  *
15435  * Whenever the selected schema is not pg_catalog, be careful to qualify
15436  * references to system catalogs and types in our emitted commands!
15437  *
15438  * This function is called only from selectSourceSchemaOnAH and
15439  * selectSourceSchema.
15440  */
15441 static void
15442 selectSourceSchema(Archive *fout, const char *schemaName)
15443 {
15444         PQExpBuffer query;
15445
15446         /* This is checked by the callers already */
15447         Assert(schemaName != NULL && *schemaName != '\0');
15448
15449         /* Not relevant if fetching from pre-7.3 DB */
15450         if (fout->remoteVersion < 70300)
15451                 return;
15452
15453         query = createPQExpBuffer();
15454         appendPQExpBuffer(query, "SET search_path = %s",
15455                                           fmtId(schemaName));
15456         if (strcmp(schemaName, "pg_catalog") != 0)
15457                 appendPQExpBufferStr(query, ", pg_catalog");
15458
15459         ExecuteSqlStatement(fout, query->data);
15460
15461         destroyPQExpBuffer(query);
15462 }
15463
15464 /*
15465  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15466  * given type name.
15467  *
15468  * NB: in 7.3 and up the result may depend on the currently-selected
15469  * schema; this is why we don't try to cache the names.
15470  */
15471 static char *
15472 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15473 {
15474         char       *result;
15475         PQExpBuffer query;
15476         PGresult   *res;
15477
15478         if (oid == 0)
15479         {
15480                 if ((opts & zeroAsOpaque) != 0)
15481                         return pg_strdup(g_opaque_type);
15482                 else if ((opts & zeroAsAny) != 0)
15483                         return pg_strdup("'any'");
15484                 else if ((opts & zeroAsStar) != 0)
15485                         return pg_strdup("*");
15486                 else if ((opts & zeroAsNone) != 0)
15487                         return pg_strdup("NONE");
15488         }
15489
15490         query = createPQExpBuffer();
15491         if (fout->remoteVersion >= 70300)
15492         {
15493                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15494                                                   oid);
15495         }
15496         else if (fout->remoteVersion >= 70100)
15497         {
15498                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15499                                                   oid);
15500         }
15501         else
15502         {
15503                 appendPQExpBuffer(query, "SELECT typname "
15504                                                   "FROM pg_type "
15505                                                   "WHERE oid = '%u'::oid",
15506                                                   oid);
15507         }
15508
15509         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15510
15511         if (fout->remoteVersion >= 70100)
15512         {
15513                 /* already quoted */
15514                 result = pg_strdup(PQgetvalue(res, 0, 0));
15515         }
15516         else
15517         {
15518                 /* may need to quote it */
15519                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15520         }
15521
15522         PQclear(res);
15523         destroyPQExpBuffer(query);
15524
15525         return result;
15526 }
15527
15528 /*
15529  * myFormatType --- local implementation of format_type for use with 7.0.
15530  */
15531 static char *
15532 myFormatType(const char *typname, int32 typmod)
15533 {
15534         char       *result;
15535         bool            isarray = false;
15536         PQExpBuffer buf = createPQExpBuffer();
15537
15538         /* Handle array types */
15539         if (typname[0] == '_')
15540         {
15541                 isarray = true;
15542                 typname++;
15543         }
15544
15545         /* Show lengths on bpchar and varchar */
15546         if (strcmp(typname, "bpchar") == 0)
15547         {
15548                 int                     len = (typmod - VARHDRSZ);
15549
15550                 appendPQExpBufferStr(buf, "character");
15551                 if (len > 1)
15552                         appendPQExpBuffer(buf, "(%d)",
15553                                                           typmod - VARHDRSZ);
15554         }
15555         else if (strcmp(typname, "varchar") == 0)
15556         {
15557                 appendPQExpBufferStr(buf, "character varying");
15558                 if (typmod != -1)
15559                         appendPQExpBuffer(buf, "(%d)",
15560                                                           typmod - VARHDRSZ);
15561         }
15562         else if (strcmp(typname, "numeric") == 0)
15563         {
15564                 appendPQExpBufferStr(buf, "numeric");
15565                 if (typmod != -1)
15566                 {
15567                         int32           tmp_typmod;
15568                         int                     precision;
15569                         int                     scale;
15570
15571                         tmp_typmod = typmod - VARHDRSZ;
15572                         precision = (tmp_typmod >> 16) & 0xffff;
15573                         scale = tmp_typmod & 0xffff;
15574                         appendPQExpBuffer(buf, "(%d,%d)",
15575                                                           precision, scale);
15576                 }
15577         }
15578
15579         /*
15580          * char is an internal single-byte data type; Let's make sure we force it
15581          * through with quotes. - thomas 1998-12-13
15582          */
15583         else if (strcmp(typname, "char") == 0)
15584                 appendPQExpBufferStr(buf, "\"char\"");
15585         else
15586                 appendPQExpBufferStr(buf, fmtId(typname));
15587
15588         /* Append array qualifier for array types */
15589         if (isarray)
15590                 appendPQExpBufferStr(buf, "[]");
15591
15592         result = pg_strdup(buf->data);
15593         destroyPQExpBuffer(buf);
15594
15595         return result;
15596 }
15597
15598 /*
15599  * Return a column list clause for the given relation.
15600  *
15601  * Special case: if there are no undropped columns in the relation, return
15602  * "", not an invalid "()" column list.
15603  */
15604 static const char *
15605 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15606 {
15607         int                     numatts = ti->numatts;
15608         char      **attnames = ti->attnames;
15609         bool       *attisdropped = ti->attisdropped;
15610         bool            needComma;
15611         int                     i;
15612
15613         appendPQExpBufferChar(buffer, '(');
15614         needComma = false;
15615         for (i = 0; i < numatts; i++)
15616         {
15617                 if (attisdropped[i])
15618                         continue;
15619                 if (needComma)
15620                         appendPQExpBufferStr(buffer, ", ");
15621                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
15622                 needComma = true;
15623         }
15624
15625         if (!needComma)
15626                 return "";                              /* no undropped columns */
15627
15628         appendPQExpBufferChar(buffer, ')');
15629         return buffer->data;
15630 }
15631
15632 /*
15633  * Execute an SQL query and verify that we got exactly one row back.
15634  */
15635 static PGresult *
15636 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15637 {
15638         PGresult   *res;
15639         int                     ntups;
15640
15641         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15642
15643         /* Expecting a single result only */
15644         ntups = PQntuples(res);
15645         if (ntups != 1)
15646                 exit_horribly(NULL,
15647                                           ngettext("query returned %d row instead of one: %s\n",
15648                                                            "query returned %d rows instead of one: %s\n",
15649                                                            ntups),
15650                                           ntups, query);
15651
15652         return res;
15653 }