]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Allow aggregates to provide estimates of their transition state data size.
[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-2013, 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 extern char *optarg;
67 extern int      optind,
68                         opterr;
69
70
71 typedef struct
72 {
73         const char *descr;                      /* comment for an object */
74         Oid                     classoid;               /* object class (catalog OID) */
75         Oid                     objoid;                 /* object OID */
76         int                     objsubid;               /* subobject (table column #) */
77 } CommentItem;
78
79 typedef struct
80 {
81         const char *provider;           /* label provider of this security label */
82         const char *label;                      /* security label for an object */
83         Oid                     classoid;               /* object class (catalog OID) */
84         Oid                     objoid;                 /* object OID */
85         int                     objsubid;               /* subobject (table column #) */
86 } SecLabelItem;
87
88 /* global decls */
89 bool            g_verbose;                      /* User wants verbose narration of our
90                                                                  * activities. */
91
92 /* various user-settable parameters */
93 bool            schemaOnly;
94 bool            dataOnly;
95 int                     dumpSections;           /* bitmask of chosen sections */
96 bool            aclsSkip;
97 const char *lockWaitTimeout;
98
99 /* subquery used to convert user ID (eg, datdba) to user name */
100 static const char *username_subquery;
101
102 /* obsolete as of 7.3: */
103 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
104
105 /*
106  * Object inclusion/exclusion lists
107  *
108  * The string lists record the patterns given by command-line switches,
109  * which we then convert to lists of OIDs of matching objects.
110  */
111 static SimpleStringList schema_include_patterns = {NULL, NULL};
112 static SimpleOidList schema_include_oids = {NULL, NULL};
113 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
114 static SimpleOidList schema_exclude_oids = {NULL, NULL};
115
116 static SimpleStringList table_include_patterns = {NULL, NULL};
117 static SimpleOidList table_include_oids = {NULL, NULL};
118 static SimpleStringList table_exclude_patterns = {NULL, NULL};
119 static SimpleOidList table_exclude_oids = {NULL, NULL};
120 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
121 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
122
123 /* default, if no "inclusion" switches appear, is to dump everything */
124 static bool include_everything = true;
125
126 char            g_opaque_type[10];      /* name for the opaque type */
127
128 /* placeholders for the delimiters for comments */
129 char            g_comment_start[10];
130 char            g_comment_end[10];
131
132 static const CatalogId nilCatalogId = {0, 0};
133
134 /* flags for various command-line long options */
135 static int      binary_upgrade = 0;
136 static int      disable_dollar_quoting = 0;
137 static int      dump_inserts = 0;
138 static int      column_inserts = 0;
139 static int      no_security_labels = 0;
140 static int      no_synchronized_snapshots = 0;
141 static int      no_unlogged_table_data = 0;
142 static int      serializable_deferrable = 0;
143
144
145 static void help(const char *progname);
146 static void setup_connection(Archive *AH, const char *dumpencoding,
147                                  char *use_role);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(Archive *fout,
150                                                         SimpleStringList *patterns,
151                                                         SimpleOidList *oids);
152 static void expand_table_name_patterns(Archive *fout,
153                                                    SimpleStringList *patterns,
154                                                    SimpleOidList *oids);
155 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
156 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
157 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
158 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
159 static void dumpComment(Archive *fout, const char *target,
160                         const char *namespace, const char *owner,
161                         CatalogId catalogId, int subid, DumpId dumpId);
162 static int findComments(Archive *fout, Oid classoid, Oid objoid,
163                          CommentItem **items);
164 static int      collectComments(Archive *fout, CommentItem **items);
165 static void dumpSecLabel(Archive *fout, const char *target,
166                          const char *namespace, const char *owner,
167                          CatalogId catalogId, int subid, DumpId dumpId);
168 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
169                           SecLabelItem **items);
170 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
171 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
172 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
173 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
174 static void dumpType(Archive *fout, TypeInfo *tyinfo);
175 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
176 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
179 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
181 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
182 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
183 static void dumpFunc(Archive *fout, FuncInfo *finfo);
184 static void dumpCast(Archive *fout, CastInfo *cast);
185 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
186 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
187 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
188 static void dumpCollation(Archive *fout, CollInfo *convinfo);
189 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
190 static void dumpRule(Archive *fout, RuleInfo *rinfo);
191 static void dumpAgg(Archive *fout, AggInfo *agginfo);
192 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
193 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
194 static void dumpTable(Archive *fout, TableInfo *tbinfo);
195 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
196 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
197 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
198 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
199 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
200 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
201 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
202 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
203 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
204 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
205 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
206 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
207 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
208 static void dumpUserMappings(Archive *fout,
209                                  const char *servername, const char *namespace,
210                                  const char *owner, CatalogId catalogId, DumpId dumpId);
211 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
212
213 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
214                 const char *type, const char *name, const char *subname,
215                 const char *tag, const char *nspname, const char *owner,
216                 const char *acls);
217
218 static void getDependencies(Archive *fout);
219 static void BuildArchiveDependencies(Archive *fout);
220 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
221                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
222
223 static DumpableObject *createBoundaryObjects(void);
224 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
225                                                 DumpableObject *boundaryObjs);
226
227 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
228 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
229 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
230 static void buildMatViewRefreshDependencies(Archive *fout);
231 static void getTableDataFKConstraints(void);
232 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
233                                                                            bool is_agg);
234 static char *format_function_arguments_old(Archive *fout,
235                                                           FuncInfo *finfo, int nallargs,
236                                                           char **allargtypes,
237                                                           char **argmodes,
238                                                           char **argnames);
239 static char *format_function_signature(Archive *fout,
240                                                   FuncInfo *finfo, bool honor_quotes);
241 static const char *convertRegProcReference(Archive *fout,
242                                                 const char *proc);
243 static const char *convertOperatorReference(Archive *fout, const char *opr);
244 static const char *convertTSFunction(Archive *fout, Oid funcOid);
245 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
246 static Oid      findLastBuiltinOid_V70(Archive *fout);
247 static void selectSourceSchema(Archive *fout, const char *schemaName);
248 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
249 static char *myFormatType(const char *typname, int32 typmod);
250 static void getBlobs(Archive *fout);
251 static void dumpBlob(Archive *fout, BlobInfo *binfo);
252 static int      dumpBlobs(Archive *fout, void *arg);
253 static void dumpDatabase(Archive *AH);
254 static void dumpEncoding(Archive *AH);
255 static void dumpStdStrings(Archive *AH);
256 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
257                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
258 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
259                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
260 static void binary_upgrade_set_pg_class_oids(Archive *fout,
261                                                                  PQExpBuffer upgrade_buffer,
262                                                                  Oid pg_class_oid, bool is_index);
263 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
264                                                                 DumpableObject *dobj,
265                                                                 const char *objlabel);
266 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
267 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
268 static char *get_synchronized_snapshot(Archive *fout);
269 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
270 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
271
272
273 int
274 main(int argc, char **argv)
275 {
276         int                     c;
277         const char *filename = NULL;
278         const char *format = "p";
279         const char *dbname = NULL;
280         const char *pghost = NULL;
281         const char *pgport = NULL;
282         const char *username = NULL;
283         const char *dumpencoding = NULL;
284         bool            oids = false;
285         TableInfo  *tblinfo;
286         int                     numTables;
287         DumpableObject **dobjs;
288         int                     numObjs;
289         DumpableObject *boundaryObjs;
290         int                     i;
291         int                     numWorkers = 1;
292         enum trivalue prompt_password = TRI_DEFAULT;
293         int                     compressLevel = -1;
294         int                     plainText = 0;
295         int                     outputClean = 0;
296         int                     outputCreateDB = 0;
297         bool            outputBlobs = false;
298         int                     outputNoOwner = 0;
299         char       *outputSuperuser = NULL;
300         char       *use_role = NULL;
301         int                     optindex;
302         RestoreOptions *ropt;
303         ArchiveFormat archiveFormat = archUnknown;
304         ArchiveMode archiveMode;
305         Archive    *fout;                       /* the script file */
306
307         static int      disable_triggers = 0;
308         static int      outputNoTablespaces = 0;
309         static int      use_setsessauth = 0;
310
311         static struct option long_options[] = {
312                 {"data-only", no_argument, NULL, 'a'},
313                 {"blobs", no_argument, NULL, 'b'},
314                 {"clean", no_argument, NULL, 'c'},
315                 {"create", no_argument, NULL, 'C'},
316                 {"dbname", required_argument, NULL, 'd'},
317                 {"file", required_argument, NULL, 'f'},
318                 {"format", required_argument, NULL, 'F'},
319                 {"host", required_argument, NULL, 'h'},
320                 {"ignore-version", no_argument, NULL, 'i'},
321                 {"jobs", 1, NULL, 'j'},
322                 {"no-reconnect", no_argument, NULL, 'R'},
323                 {"oids", no_argument, NULL, 'o'},
324                 {"no-owner", no_argument, NULL, 'O'},
325                 {"port", required_argument, NULL, 'p'},
326                 {"schema", required_argument, NULL, 'n'},
327                 {"exclude-schema", required_argument, NULL, 'N'},
328                 {"schema-only", no_argument, NULL, 's'},
329                 {"superuser", required_argument, NULL, 'S'},
330                 {"table", required_argument, NULL, 't'},
331                 {"exclude-table", required_argument, NULL, 'T'},
332                 {"no-password", no_argument, NULL, 'w'},
333                 {"password", no_argument, NULL, 'W'},
334                 {"username", required_argument, NULL, 'U'},
335                 {"verbose", no_argument, NULL, 'v'},
336                 {"no-privileges", no_argument, NULL, 'x'},
337                 {"no-acl", no_argument, NULL, 'x'},
338                 {"compress", required_argument, NULL, 'Z'},
339                 {"encoding", required_argument, NULL, 'E'},
340                 {"help", no_argument, NULL, '?'},
341                 {"version", no_argument, NULL, 'V'},
342
343                 /*
344                  * the following options don't have an equivalent short option letter
345                  */
346                 {"attribute-inserts", no_argument, &column_inserts, 1},
347                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
348                 {"column-inserts", no_argument, &column_inserts, 1},
349                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
350                 {"disable-triggers", no_argument, &disable_triggers, 1},
351                 {"exclude-table-data", required_argument, NULL, 4},
352                 {"inserts", no_argument, &dump_inserts, 1},
353                 {"lock-wait-timeout", required_argument, NULL, 2},
354                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
355                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
356                 {"role", required_argument, NULL, 3},
357                 {"section", required_argument, NULL, 5},
358                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
359                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
360                 {"no-security-labels", no_argument, &no_security_labels, 1},
361                 {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
362                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
363
364                 {NULL, 0, NULL, 0}
365         };
366
367         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
368
369         /*
370          * Initialize what we need for parallel execution, especially for thread
371          * support on Windows.
372          */
373         init_parallel_dump_utils();
374
375         g_verbose = false;
376
377         strcpy(g_comment_start, "-- ");
378         g_comment_end[0] = '\0';
379         strcpy(g_opaque_type, "opaque");
380
381         dataOnly = schemaOnly = false;
382         dumpSections = DUMP_UNSECTIONED;
383         lockWaitTimeout = NULL;
384
385         progname = get_progname(argv[0]);
386
387         /* Set default options based on progname */
388         if (strcmp(progname, "pg_backup") == 0)
389                 format = "c";
390
391         if (argc > 1)
392         {
393                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
394                 {
395                         help(progname);
396                         exit_nicely(0);
397                 }
398                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
399                 {
400                         puts("pg_dump (PostgreSQL) " PG_VERSION);
401                         exit_nicely(0);
402                 }
403         }
404
405         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:K:n:N:oOp:RsS:t:T:U:vwWxZ:",
406                                                         long_options, &optindex)) != -1)
407         {
408                 switch (c)
409                 {
410                         case 'a':                       /* Dump data only */
411                                 dataOnly = true;
412                                 break;
413
414                         case 'b':                       /* Dump blobs */
415                                 outputBlobs = true;
416                                 break;
417
418                         case 'c':                       /* clean (i.e., drop) schema prior to create */
419                                 outputClean = 1;
420                                 break;
421
422                         case 'C':                       /* Create DB */
423                                 outputCreateDB = 1;
424                                 break;
425
426                         case 'd':                       /* database name */
427                                 dbname = pg_strdup(optarg);
428                                 break;
429
430                         case 'E':                       /* Dump encoding */
431                                 dumpencoding = pg_strdup(optarg);
432                                 break;
433
434                         case 'f':
435                                 filename = pg_strdup(optarg);
436                                 break;
437
438                         case 'F':
439                                 format = pg_strdup(optarg);
440                                 break;
441
442                         case 'h':                       /* server host */
443                                 pghost = pg_strdup(optarg);
444                                 break;
445
446                         case 'i':
447                                 /* ignored, deprecated option */
448                                 break;
449
450                         case 'j':                       /* number of dump jobs */
451                                 numWorkers = atoi(optarg);
452                                 break;
453
454                         case 'n':                       /* include schema(s) */
455                                 simple_string_list_append(&schema_include_patterns, optarg);
456                                 include_everything = false;
457                                 break;
458
459                         case 'N':                       /* exclude schema(s) */
460                                 simple_string_list_append(&schema_exclude_patterns, optarg);
461                                 break;
462
463                         case 'o':                       /* Dump oids */
464                                 oids = true;
465                                 break;
466
467                         case 'O':                       /* Don't reconnect to match owner */
468                                 outputNoOwner = 1;
469                                 break;
470
471                         case 'p':                       /* server port */
472                                 pgport = pg_strdup(optarg);
473                                 break;
474
475                         case 'R':
476                                 /* no-op, still accepted for backwards compatibility */
477                                 break;
478
479                         case 's':                       /* dump schema only */
480                                 schemaOnly = true;
481                                 break;
482
483                         case 'S':                       /* Username for superuser in plain text output */
484                                 outputSuperuser = pg_strdup(optarg);
485                                 break;
486
487                         case 't':                       /* include table(s) */
488                                 simple_string_list_append(&table_include_patterns, optarg);
489                                 include_everything = false;
490                                 break;
491
492                         case 'T':                       /* exclude table(s) */
493                                 simple_string_list_append(&table_exclude_patterns, optarg);
494                                 break;
495
496                         case 'U':
497                                 username = pg_strdup(optarg);
498                                 break;
499
500                         case 'v':                       /* verbose */
501                                 g_verbose = true;
502                                 break;
503
504                         case 'w':
505                                 prompt_password = TRI_NO;
506                                 break;
507
508                         case 'W':
509                                 prompt_password = TRI_YES;
510                                 break;
511
512                         case 'x':                       /* skip ACL dump */
513                                 aclsSkip = true;
514                                 break;
515
516                         case 'Z':                       /* Compression Level */
517                                 compressLevel = atoi(optarg);
518                                 break;
519
520                         case 0:
521                                 /* This covers the long options. */
522                                 break;
523
524                         case 2:                         /* lock-wait-timeout */
525                                 lockWaitTimeout = pg_strdup(optarg);
526                                 break;
527
528                         case 3:                         /* SET ROLE */
529                                 use_role = pg_strdup(optarg);
530                                 break;
531
532                         case 4:                         /* exclude table(s) data */
533                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
534                                 break;
535
536                         case 5:                         /* section */
537                                 set_dump_section(optarg, &dumpSections);
538                                 break;
539
540                         default:
541                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
542                                 exit_nicely(1);
543                 }
544         }
545
546         /*
547          * Non-option argument specifies database name as long as it wasn't
548          * already specified with -d / --dbname
549          */
550         if (optind < argc && dbname == NULL)
551                 dbname = argv[optind++];
552
553         /* Complain if any arguments remain */
554         if (optind < argc)
555         {
556                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
557                                 progname, argv[optind]);
558                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
559                                 progname);
560                 exit_nicely(1);
561         }
562
563         /* --column-inserts implies --inserts */
564         if (column_inserts)
565                 dump_inserts = 1;
566
567         if (dataOnly && schemaOnly)
568                 exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
569
570         if (dataOnly && outputClean)
571                 exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
572
573         if (dump_inserts && oids)
574         {
575                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
576                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
577                 exit_nicely(1);
578         }
579
580         /* Identify archive format to emit */
581         archiveFormat = parseArchiveFormat(format, &archiveMode);
582
583         /* archiveFormat specific setup */
584         if (archiveFormat == archNull)
585                 plainText = 1;
586
587         /* Custom and directory formats are compressed by default, others not */
588         if (compressLevel == -1)
589         {
590                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
591                         compressLevel = Z_DEFAULT_COMPRESSION;
592                 else
593                         compressLevel = 0;
594         }
595
596         /*
597          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
598          * parallel jobs because that's the maximum limit for the
599          * WaitForMultipleObjects() call.
600          */
601         if (numWorkers <= 0
602 #ifdef WIN32
603                 || numWorkers > MAXIMUM_WAIT_OBJECTS
604 #endif
605                 )
606                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
607
608         /* Parallel backup only in the directory archive format so far */
609         if (archiveFormat != archDirectory && numWorkers > 1)
610                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
611
612         /* Open the output file */
613         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
614                                                  setupDumpWorker);
615
616         /* Register the cleanup hook */
617         on_exit_close_archive(fout);
618
619         if (fout == NULL)
620                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
621
622         /* Let the archiver know how noisy to be */
623         fout->verbose = g_verbose;
624
625         /*
626          * We allow the server to be back to 7.0, and up to any minor release of
627          * our own major version.  (See also version check in pg_dumpall.c.)
628          */
629         fout->minRemoteVersion = 70000;
630         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
631
632         fout->numWorkers = numWorkers;
633
634         /*
635          * Open the database using the Archiver, so it knows about it. Errors mean
636          * death.
637          */
638         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
639         setup_connection(fout, dumpencoding, use_role);
640
641         /*
642          * Disable security label support if server version < v9.1.x (prevents
643          * access to nonexistent pg_seclabel catalog)
644          */
645         if (fout->remoteVersion < 90100)
646                 no_security_labels = 1;
647
648         /*
649          * When running against 9.0 or later, check if we are in recovery mode,
650          * which means we are on a hot standby.
651          */
652         if (fout->remoteVersion >= 90000)
653         {
654                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
655
656                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
657                 {
658                         /*
659                          * On hot standby slaves, never try to dump unlogged table data,
660                          * since it will just throw an error.
661                          */
662                         no_unlogged_table_data = true;
663                 }
664                 PQclear(res);
665         }
666
667         /* Select the appropriate subquery to convert user IDs to names */
668         if (fout->remoteVersion >= 80100)
669                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
670         else if (fout->remoteVersion >= 70300)
671                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
672         else
673                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
674
675         /* check the version for the synchronized snapshots feature */
676         if (numWorkers > 1 && fout->remoteVersion < 90200
677                 && !no_synchronized_snapshots)
678                 exit_horribly(NULL,
679                  "Synchronized snapshots are not supported by this server version.\n"
680                   "Run with --no-synchronized-snapshots instead if you do not need\n"
681                                           "synchronized snapshots.\n");
682
683         /* Find the last built-in OID, if needed */
684         if (fout->remoteVersion < 70300)
685         {
686                 if (fout->remoteVersion >= 70100)
687                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
688                                                                                                   PQdb(GetConnection(fout)));
689                 else
690                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
691                 if (g_verbose)
692                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
693         }
694
695         /* Expand schema selection patterns into OID lists */
696         if (schema_include_patterns.head != NULL)
697         {
698                 expand_schema_name_patterns(fout, &schema_include_patterns,
699                                                                         &schema_include_oids);
700                 if (schema_include_oids.head == NULL)
701                         exit_horribly(NULL, "No matching schemas were found\n");
702         }
703         expand_schema_name_patterns(fout, &schema_exclude_patterns,
704                                                                 &schema_exclude_oids);
705         /* non-matching exclusion patterns aren't an error */
706
707         /* Expand table selection patterns into OID lists */
708         if (table_include_patterns.head != NULL)
709         {
710                 expand_table_name_patterns(fout, &table_include_patterns,
711                                                                    &table_include_oids);
712                 if (table_include_oids.head == NULL)
713                         exit_horribly(NULL, "No matching tables were found\n");
714         }
715         expand_table_name_patterns(fout, &table_exclude_patterns,
716                                                            &table_exclude_oids);
717
718         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
719                                                            &tabledata_exclude_oids);
720
721         /* non-matching exclusion patterns aren't an error */
722
723         /*
724          * Dumping blobs is now default unless we saw an inclusion switch or -s
725          * ... but even if we did see one of these, -b turns it back on.
726          */
727         if (include_everything && !schemaOnly)
728                 outputBlobs = true;
729
730         /*
731          * Now scan the database and create DumpableObject structs for all the
732          * objects we intend to dump.
733          */
734         tblinfo = getSchemaData(fout, &numTables);
735
736         if (fout->remoteVersion < 80400)
737                 guessConstraintInheritance(tblinfo, numTables);
738
739         if (!schemaOnly)
740         {
741                 getTableData(tblinfo, numTables, oids);
742                 buildMatViewRefreshDependencies(fout);
743                 if (dataOnly)
744                         getTableDataFKConstraints();
745         }
746
747         if (outputBlobs)
748                 getBlobs(fout);
749
750         /*
751          * Collect dependency data to assist in ordering the objects.
752          */
753         getDependencies(fout);
754
755         /* Lastly, create dummy objects to represent the section boundaries */
756         boundaryObjs = createBoundaryObjects();
757
758         /* Get pointers to all the known DumpableObjects */
759         getDumpableObjects(&dobjs, &numObjs);
760
761         /*
762          * Add dummy dependencies to enforce the dump section ordering.
763          */
764         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
765
766         /*
767          * Sort the objects into a safe dump order (no forward references).
768          *
769          * In 7.3 or later, we can rely on dependency information to help us
770          * determine a safe order, so the initial sort is mostly for cosmetic
771          * purposes: we sort by name to ensure that logically identical schemas
772          * will dump identically.  Before 7.3 we don't have dependencies and we
773          * use OID ordering as an (unreliable) guide to creation order.
774          */
775         if (fout->remoteVersion >= 70300)
776                 sortDumpableObjectsByTypeName(dobjs, numObjs);
777         else
778                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
779
780         /* If we do a parallel dump, we want the largest tables to go first */
781         if (archiveFormat == archDirectory && numWorkers > 1)
782                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
783
784         sortDumpableObjects(dobjs, numObjs,
785                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
786
787         /*
788          * Create archive TOC entries for all the objects to be dumped, in a safe
789          * order.
790          */
791
792         /* First the special ENCODING and STDSTRINGS entries. */
793         dumpEncoding(fout);
794         dumpStdStrings(fout);
795
796         /* The database item is always next, unless we don't want it at all */
797         if (include_everything && !dataOnly)
798                 dumpDatabase(fout);
799
800         /* Now the rearrangeable objects. */
801         for (i = 0; i < numObjs; i++)
802                 dumpDumpableObject(fout, dobjs[i]);
803
804         /*
805          * Set up options info to ensure we dump what we want.
806          */
807         ropt = NewRestoreOptions();
808         ropt->filename = filename;
809         ropt->dropSchema = outputClean;
810         ropt->dataOnly = dataOnly;
811         ropt->schemaOnly = schemaOnly;
812         ropt->dumpSections = dumpSections;
813         ropt->aclsSkip = aclsSkip;
814         ropt->superuser = outputSuperuser;
815         ropt->createDB = outputCreateDB;
816         ropt->noOwner = outputNoOwner;
817         ropt->noTablespace = outputNoTablespaces;
818         ropt->disable_triggers = disable_triggers;
819         ropt->use_setsessauth = use_setsessauth;
820
821         if (compressLevel == -1)
822                 ropt->compression = 0;
823         else
824                 ropt->compression = compressLevel;
825
826         ropt->suppressDumpWarnings = true;      /* We've already shown them */
827
828         SetArchiveRestoreOptions(fout, ropt);
829
830         /*
831          * The archive's TOC entries are now marked as to which ones will actually
832          * be output, so we can set up their dependency lists properly. This isn't
833          * necessary for plain-text output, though.
834          */
835         if (!plainText)
836                 BuildArchiveDependencies(fout);
837
838         /*
839          * And finally we can do the actual output.
840          *
841          * Note: for non-plain-text output formats, the output file is written
842          * inside CloseArchive().  This is, um, bizarre; but not worth changing
843          * right now.
844          */
845         if (plainText)
846                 RestoreArchive(fout);
847
848         CloseArchive(fout);
849
850         exit_nicely(0);
851 }
852
853
854 static void
855 help(const char *progname)
856 {
857         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
858         printf(_("Usage:\n"));
859         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
860
861         printf(_("\nGeneral options:\n"));
862         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
863         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
864                          "                               plain text (default))\n"));
865         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
866         printf(_("  -v, --verbose                verbose mode\n"));
867         printf(_("  -V, --version                output version information, then exit\n"));
868         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
869         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
870         printf(_("  -?, --help                   show this help, then exit\n"));
871
872         printf(_("\nOptions controlling the output content:\n"));
873         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
874         printf(_("  -b, --blobs                  include large objects in dump\n"));
875         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
876         printf(_("  -C, --create                 include commands to create database in dump\n"));
877         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
878         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
879         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
880         printf(_("  -o, --oids                   include OIDs in dump\n"));
881         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
882                          "                               plain-text format\n"));
883         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
884         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
885         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
886         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
887         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
888         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
889         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
890         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
891         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
892         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
893         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
894         printf(_("  --no-security-labels         do not dump security label assignments\n"));
895         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
896         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
897         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
898         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
899         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
900         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
901         printf(_("  --use-set-session-authorization\n"
902                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
903                          "                               ALTER OWNER commands to set ownership\n"));
904
905         printf(_("\nConnection options:\n"));
906         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
907         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
908         printf(_("  -p, --port=PORT          database server port number\n"));
909         printf(_("  -U, --username=NAME      connect as specified database user\n"));
910         printf(_("  -w, --no-password        never prompt for password\n"));
911         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
912         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
913
914         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
915                          "variable value is used.\n\n"));
916         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
917 }
918
919 static void
920 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
921 {
922         PGconn     *conn = GetConnection(AH);
923         const char *std_strings;
924
925         /*
926          * Set the client encoding if requested. If dumpencoding == NULL then
927          * either it hasn't been requested or we're a cloned connection and then
928          * this has already been set in CloneArchive according to the original
929          * connection encoding.
930          */
931         if (dumpencoding)
932         {
933                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
934                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
935                                                   dumpencoding);
936         }
937
938         /*
939          * Get the active encoding and the standard_conforming_strings setting, so
940          * we know how to escape strings.
941          */
942         AH->encoding = PQclientEncoding(conn);
943
944         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
945         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
946
947         /* Set the role if requested */
948         if (!use_role && AH->use_role)
949                 use_role = AH->use_role;
950
951         /* Set the role if requested */
952         if (use_role && AH->remoteVersion >= 80100)
953         {
954                 PQExpBuffer query = createPQExpBuffer();
955
956                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
957                 ExecuteSqlStatement(AH, query->data);
958                 destroyPQExpBuffer(query);
959
960                 /* save this for later use on parallel connections */
961                 if (!AH->use_role)
962                         AH->use_role = strdup(use_role);
963         }
964
965         /* Set the datestyle to ISO to ensure the dump's portability */
966         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
967
968         /* Likewise, avoid using sql_standard intervalstyle */
969         if (AH->remoteVersion >= 80400)
970                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
971
972         /*
973          * If supported, set extra_float_digits so that we can dump float data
974          * exactly (given correctly implemented float I/O code, anyway)
975          */
976         if (AH->remoteVersion >= 90000)
977                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
978         else if (AH->remoteVersion >= 70400)
979                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
980
981         /*
982          * If synchronized scanning is supported, disable it, to prevent
983          * unpredictable changes in row ordering across a dump and reload.
984          */
985         if (AH->remoteVersion >= 80300)
986                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
987
988         /*
989          * Disable timeouts if supported.
990          */
991         if (AH->remoteVersion >= 70300)
992                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
993         if (AH->remoteVersion >= 90300)
994                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
995
996         /*
997          * Quote all identifiers, if requested.
998          */
999         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1000                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1001
1002         /*
1003          * Start transaction-snapshot mode transaction to dump consistent data.
1004          */
1005         ExecuteSqlStatement(AH, "BEGIN");
1006         if (AH->remoteVersion >= 90100)
1007         {
1008                 if (serializable_deferrable)
1009                         ExecuteSqlStatement(AH,
1010                                                                 "SET TRANSACTION ISOLATION LEVEL "
1011                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1012                 else
1013                         ExecuteSqlStatement(AH,
1014                                                                 "SET TRANSACTION ISOLATION LEVEL "
1015                                                                 "REPEATABLE READ, READ ONLY");
1016         }
1017         else if (AH->remoteVersion >= 70400)
1018         {
1019                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1020                 ExecuteSqlStatement(AH,
1021                                                         "SET TRANSACTION ISOLATION LEVEL "
1022                                                         "SERIALIZABLE READ ONLY");
1023         }
1024         else
1025                 ExecuteSqlStatement(AH,
1026                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1027
1028
1029
1030         if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
1031         {
1032                 if (AH->sync_snapshot_id)
1033                 {
1034                         PQExpBuffer query = createPQExpBuffer();
1035
1036                         appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1037                         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1038                         ExecuteSqlStatement(AH, query->data);
1039                         destroyPQExpBuffer(query);
1040                 }
1041                 else
1042                         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1043         }
1044 }
1045
1046 static void
1047 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
1048 {
1049         setup_connection(AHX, NULL, NULL);
1050 }
1051
1052 static char *
1053 get_synchronized_snapshot(Archive *fout)
1054 {
1055         char       *query = "SELECT pg_export_snapshot()";
1056         char       *result;
1057         PGresult   *res;
1058
1059         res = ExecuteSqlQueryForSingleRow(fout, query);
1060         result = strdup(PQgetvalue(res, 0, 0));
1061         PQclear(res);
1062
1063         return result;
1064 }
1065
1066 static ArchiveFormat
1067 parseArchiveFormat(const char *format, ArchiveMode *mode)
1068 {
1069         ArchiveFormat archiveFormat;
1070
1071         *mode = archModeWrite;
1072
1073         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1074         {
1075                 /* This is used by pg_dumpall, and is not documented */
1076                 archiveFormat = archNull;
1077                 *mode = archModeAppend;
1078         }
1079         else if (pg_strcasecmp(format, "c") == 0)
1080                 archiveFormat = archCustom;
1081         else if (pg_strcasecmp(format, "custom") == 0)
1082                 archiveFormat = archCustom;
1083         else if (pg_strcasecmp(format, "d") == 0)
1084                 archiveFormat = archDirectory;
1085         else if (pg_strcasecmp(format, "directory") == 0)
1086                 archiveFormat = archDirectory;
1087         else if (pg_strcasecmp(format, "p") == 0)
1088                 archiveFormat = archNull;
1089         else if (pg_strcasecmp(format, "plain") == 0)
1090                 archiveFormat = archNull;
1091         else if (pg_strcasecmp(format, "t") == 0)
1092                 archiveFormat = archTar;
1093         else if (pg_strcasecmp(format, "tar") == 0)
1094                 archiveFormat = archTar;
1095         else
1096                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1097         return archiveFormat;
1098 }
1099
1100 /*
1101  * Find the OIDs of all schemas matching the given list of patterns,
1102  * and append them to the given OID list.
1103  */
1104 static void
1105 expand_schema_name_patterns(Archive *fout,
1106                                                         SimpleStringList *patterns,
1107                                                         SimpleOidList *oids)
1108 {
1109         PQExpBuffer query;
1110         PGresult   *res;
1111         SimpleStringListCell *cell;
1112         int                     i;
1113
1114         if (patterns->head == NULL)
1115                 return;                                 /* nothing to do */
1116
1117         if (fout->remoteVersion < 70300)
1118                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1119
1120         query = createPQExpBuffer();
1121
1122         /*
1123          * We use UNION ALL rather than UNION; this might sometimes result in
1124          * duplicate entries in the OID list, but we don't care.
1125          */
1126
1127         for (cell = patterns->head; cell; cell = cell->next)
1128         {
1129                 if (cell != patterns->head)
1130                         appendPQExpBuffer(query, "UNION ALL\n");
1131                 appendPQExpBuffer(query,
1132                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1133                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1134                                                           false, NULL, "n.nspname", NULL, NULL);
1135         }
1136
1137         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1138
1139         for (i = 0; i < PQntuples(res); i++)
1140         {
1141                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1142         }
1143
1144         PQclear(res);
1145         destroyPQExpBuffer(query);
1146 }
1147
1148 /*
1149  * Find the OIDs of all tables matching the given list of patterns,
1150  * and append them to the given OID list.
1151  */
1152 static void
1153 expand_table_name_patterns(Archive *fout,
1154                                                    SimpleStringList *patterns, SimpleOidList *oids)
1155 {
1156         PQExpBuffer query;
1157         PGresult   *res;
1158         SimpleStringListCell *cell;
1159         int                     i;
1160
1161         if (patterns->head == NULL)
1162                 return;                                 /* nothing to do */
1163
1164         query = createPQExpBuffer();
1165
1166         /*
1167          * We use UNION ALL rather than UNION; this might sometimes result in
1168          * duplicate entries in the OID list, but we don't care.
1169          */
1170
1171         for (cell = patterns->head; cell; cell = cell->next)
1172         {
1173                 if (cell != patterns->head)
1174                         appendPQExpBuffer(query, "UNION ALL\n");
1175                 appendPQExpBuffer(query,
1176                                                   "SELECT c.oid"
1177                                                   "\nFROM pg_catalog.pg_class c"
1178                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1179                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1180                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1181                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1182                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1183                                                           false, "n.nspname", "c.relname", NULL,
1184                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1185         }
1186
1187         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1188
1189         for (i = 0; i < PQntuples(res); i++)
1190         {
1191                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1192         }
1193
1194         PQclear(res);
1195         destroyPQExpBuffer(query);
1196 }
1197
1198 /*
1199  * selectDumpableNamespace: policy-setting subroutine
1200  *              Mark a namespace as to be dumped or not
1201  */
1202 static void
1203 selectDumpableNamespace(NamespaceInfo *nsinfo)
1204 {
1205         /*
1206          * If specific tables are being dumped, do not dump any complete
1207          * namespaces. If specific namespaces are being dumped, dump just those
1208          * namespaces. Otherwise, dump all non-system namespaces.
1209          */
1210         if (table_include_oids.head != NULL)
1211                 nsinfo->dobj.dump = false;
1212         else if (schema_include_oids.head != NULL)
1213                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1214                                                                                                    nsinfo->dobj.catId.oid);
1215         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1216                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1217                 nsinfo->dobj.dump = false;
1218         else
1219                 nsinfo->dobj.dump = true;
1220
1221         /*
1222          * In any case, a namespace can be excluded by an exclusion switch
1223          */
1224         if (nsinfo->dobj.dump &&
1225                 simple_oid_list_member(&schema_exclude_oids,
1226                                                            nsinfo->dobj.catId.oid))
1227                 nsinfo->dobj.dump = false;
1228 }
1229
1230 /*
1231  * selectDumpableTable: policy-setting subroutine
1232  *              Mark a table as to be dumped or not
1233  */
1234 static void
1235 selectDumpableTable(TableInfo *tbinfo)
1236 {
1237         /*
1238          * If specific tables are being dumped, dump just those tables; else, dump
1239          * according to the parent namespace's dump flag.
1240          */
1241         if (table_include_oids.head != NULL)
1242                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1243                                                                                                    tbinfo->dobj.catId.oid);
1244         else
1245                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1246
1247         /*
1248          * In any case, a table can be excluded by an exclusion switch
1249          */
1250         if (tbinfo->dobj.dump &&
1251                 simple_oid_list_member(&table_exclude_oids,
1252                                                            tbinfo->dobj.catId.oid))
1253                 tbinfo->dobj.dump = false;
1254 }
1255
1256 /*
1257  * selectDumpableType: policy-setting subroutine
1258  *              Mark a type as to be dumped or not
1259  *
1260  * If it's a table's rowtype or an autogenerated array type, we also apply a
1261  * special type code to facilitate sorting into the desired order.      (We don't
1262  * want to consider those to be ordinary types because that would bring tables
1263  * up into the datatype part of the dump order.)  We still set the object's
1264  * dump flag; that's not going to cause the dummy type to be dumped, but we
1265  * need it so that casts involving such types will be dumped correctly -- see
1266  * dumpCast.  This means the flag should be set the same as for the underlying
1267  * object (the table or base type).
1268  */
1269 static void
1270 selectDumpableType(TypeInfo *tyinfo)
1271 {
1272         /* skip complex types, except for standalone composite types */
1273         if (OidIsValid(tyinfo->typrelid) &&
1274                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1275         {
1276                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1277
1278                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1279                 if (tytable != NULL)
1280                         tyinfo->dobj.dump = tytable->dobj.dump;
1281                 else
1282                         tyinfo->dobj.dump = false;
1283                 return;
1284         }
1285
1286         /* skip auto-generated array types */
1287         if (tyinfo->isArray)
1288         {
1289                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1290
1291                 /*
1292                  * Fall through to set the dump flag; we assume that the subsequent
1293                  * rules will do the same thing as they would for the array's base
1294                  * type.  (We cannot reliably look up the base type here, since
1295                  * getTypes may not have processed it yet.)
1296                  */
1297         }
1298
1299         /* dump only types in dumpable namespaces */
1300         if (!tyinfo->dobj.namespace->dobj.dump)
1301                 tyinfo->dobj.dump = false;
1302
1303         /* skip undefined placeholder types */
1304         else if (!tyinfo->isDefined)
1305                 tyinfo->dobj.dump = false;
1306
1307         else
1308                 tyinfo->dobj.dump = true;
1309 }
1310
1311 /*
1312  * selectDumpableDefaultACL: policy-setting subroutine
1313  *              Mark a default ACL as to be dumped or not
1314  *
1315  * For per-schema default ACLs, dump if the schema is to be dumped.
1316  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1317  * and aclsSkip are checked separately.
1318  */
1319 static void
1320 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1321 {
1322         if (dinfo->dobj.namespace)
1323                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1324         else
1325                 dinfo->dobj.dump = include_everything;
1326 }
1327
1328 /*
1329  * selectDumpableExtension: policy-setting subroutine
1330  *              Mark an extension as to be dumped or not
1331  *
1332  * Normally, we dump all extensions, or none of them if include_everything
1333  * is false (i.e., a --schema or --table switch was given).  However, in
1334  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1335  * assume those will already be installed in the target database.  We identify
1336  * such extensions by their having OIDs in the range reserved for initdb.
1337  */
1338 static void
1339 selectDumpableExtension(ExtensionInfo *extinfo)
1340 {
1341         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1342                 extinfo->dobj.dump = false;
1343         else
1344                 extinfo->dobj.dump = include_everything;
1345 }
1346
1347 /*
1348  * selectDumpableObject: policy-setting subroutine
1349  *              Mark a generic dumpable object as to be dumped or not
1350  *
1351  * Use this only for object types without a special-case routine above.
1352  */
1353 static void
1354 selectDumpableObject(DumpableObject *dobj)
1355 {
1356         /*
1357          * Default policy is to dump if parent namespace is dumpable, or always
1358          * for non-namespace-associated items.
1359          */
1360         if (dobj->namespace)
1361                 dobj->dump = dobj->namespace->dobj.dump;
1362         else
1363                 dobj->dump = true;
1364 }
1365
1366 /*
1367  *      Dump a table's contents for loading using the COPY command
1368  *      - this routine is called by the Archiver when it wants the table
1369  *        to be dumped.
1370  */
1371
1372 static int
1373 dumpTableData_copy(Archive *fout, void *dcontext)
1374 {
1375         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1376         TableInfo  *tbinfo = tdinfo->tdtable;
1377         const char *classname = tbinfo->dobj.name;
1378         const bool      hasoids = tbinfo->hasoids;
1379         const bool      oids = tdinfo->oids;
1380         PQExpBuffer q = createPQExpBuffer();
1381
1382         /*
1383          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1384          * which uses it already.
1385          */
1386         PQExpBuffer clistBuf = createPQExpBuffer();
1387         PGconn     *conn = GetConnection(fout);
1388         PGresult   *res;
1389         int                     ret;
1390         char       *copybuf;
1391         const char *column_list;
1392
1393         if (g_verbose)
1394                 write_msg(NULL, "dumping contents of table %s\n", classname);
1395
1396         /*
1397          * Make sure we are in proper schema.  We will qualify the table name
1398          * below anyway (in case its name conflicts with a pg_catalog table); but
1399          * this ensures reproducible results in case the table contains regproc,
1400          * regclass, etc columns.
1401          */
1402         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1403
1404         /*
1405          * If possible, specify the column list explicitly so that we have no
1406          * possibility of retrieving data in the wrong column order.  (The default
1407          * column ordering of COPY will not be what we want in certain corner
1408          * cases involving ADD COLUMN and inheritance.)
1409          */
1410         if (fout->remoteVersion >= 70300)
1411                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1412         else
1413                 column_list = "";               /* can't select columns in COPY */
1414
1415         if (oids && hasoids)
1416         {
1417                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1418                                                   fmtQualifiedId(fout->remoteVersion,
1419                                                                                  tbinfo->dobj.namespace->dobj.name,
1420                                                                                  classname),
1421                                                   column_list);
1422         }
1423         else if (tdinfo->filtercond)
1424         {
1425                 /* Note: this syntax is only supported in 8.2 and up */
1426                 appendPQExpBufferStr(q, "COPY (SELECT ");
1427                 /* klugery to get rid of parens in column list */
1428                 if (strlen(column_list) > 2)
1429                 {
1430                         appendPQExpBufferStr(q, column_list + 1);
1431                         q->data[q->len - 1] = ' ';
1432                 }
1433                 else
1434                         appendPQExpBufferStr(q, "* ");
1435                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1436                                                   fmtQualifiedId(fout->remoteVersion,
1437                                                                                  tbinfo->dobj.namespace->dobj.name,
1438                                                                                  classname),
1439                                                   tdinfo->filtercond);
1440         }
1441         else
1442         {
1443                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1444                                                   fmtQualifiedId(fout->remoteVersion,
1445                                                                                  tbinfo->dobj.namespace->dobj.name,
1446                                                                                  classname),
1447                                                   column_list);
1448         }
1449         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1450         PQclear(res);
1451         destroyPQExpBuffer(clistBuf);
1452
1453         for (;;)
1454         {
1455                 ret = PQgetCopyData(conn, &copybuf, 0);
1456
1457                 if (ret < 0)
1458                         break;                          /* done or error */
1459
1460                 if (copybuf)
1461                 {
1462                         WriteData(fout, copybuf, ret);
1463                         PQfreemem(copybuf);
1464                 }
1465
1466                 /* ----------
1467                  * THROTTLE:
1468                  *
1469                  * There was considerable discussion in late July, 2000 regarding
1470                  * slowing down pg_dump when backing up large tables. Users with both
1471                  * slow & fast (multi-processor) machines experienced performance
1472                  * degradation when doing a backup.
1473                  *
1474                  * Initial attempts based on sleeping for a number of ms for each ms
1475                  * of work were deemed too complex, then a simple 'sleep in each loop'
1476                  * implementation was suggested. The latter failed because the loop
1477                  * was too tight. Finally, the following was implemented:
1478                  *
1479                  * If throttle is non-zero, then
1480                  *              See how long since the last sleep.
1481                  *              Work out how long to sleep (based on ratio).
1482                  *              If sleep is more than 100ms, then
1483                  *                      sleep
1484                  *                      reset timer
1485                  *              EndIf
1486                  * EndIf
1487                  *
1488                  * where the throttle value was the number of ms to sleep per ms of
1489                  * work. The calculation was done in each loop.
1490                  *
1491                  * Most of the hard work is done in the backend, and this solution
1492                  * still did not work particularly well: on slow machines, the ratio
1493                  * was 50:1, and on medium paced machines, 1:1, and on fast
1494                  * multi-processor machines, it had little or no effect, for reasons
1495                  * that were unclear.
1496                  *
1497                  * Further discussion ensued, and the proposal was dropped.
1498                  *
1499                  * For those people who want this feature, it can be implemented using
1500                  * gettimeofday in each loop, calculating the time since last sleep,
1501                  * multiplying that by the sleep ratio, then if the result is more
1502                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1503                  * function to sleep for a subsecond period ie.
1504                  *
1505                  * select(0, NULL, NULL, NULL, &tvi);
1506                  *
1507                  * This will return after the interval specified in the structure tvi.
1508                  * Finally, call gettimeofday again to save the 'last sleep time'.
1509                  * ----------
1510                  */
1511         }
1512         archprintf(fout, "\\.\n\n\n");
1513
1514         if (ret == -2)
1515         {
1516                 /* copy data transfer failed */
1517                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1518                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1519                 write_msg(NULL, "The command was: %s\n", q->data);
1520                 exit_nicely(1);
1521         }
1522
1523         /* Check command status and return to normal libpq state */
1524         res = PQgetResult(conn);
1525         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1526         {
1527                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1528                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1529                 write_msg(NULL, "The command was: %s\n", q->data);
1530                 exit_nicely(1);
1531         }
1532         PQclear(res);
1533
1534         destroyPQExpBuffer(q);
1535         return 1;
1536 }
1537
1538 /*
1539  * Dump table data using INSERT commands.
1540  *
1541  * Caution: when we restore from an archive file direct to database, the
1542  * INSERT commands emitted by this function have to be parsed by
1543  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1544  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1545  */
1546 static int
1547 dumpTableData_insert(Archive *fout, void *dcontext)
1548 {
1549         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1550         TableInfo  *tbinfo = tdinfo->tdtable;
1551         const char *classname = tbinfo->dobj.name;
1552         PQExpBuffer q = createPQExpBuffer();
1553         PQExpBuffer insertStmt = NULL;
1554         PGresult   *res;
1555         int                     tuple;
1556         int                     nfields;
1557         int                     field;
1558
1559         /*
1560          * Make sure we are in proper schema.  We will qualify the table name
1561          * below anyway (in case its name conflicts with a pg_catalog table); but
1562          * this ensures reproducible results in case the table contains regproc,
1563          * regclass, etc columns.
1564          */
1565         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1566
1567         if (fout->remoteVersion >= 70100)
1568         {
1569                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1570                                                   "SELECT * FROM ONLY %s",
1571                                                   fmtQualifiedId(fout->remoteVersion,
1572                                                                                  tbinfo->dobj.namespace->dobj.name,
1573                                                                                  classname));
1574         }
1575         else
1576         {
1577                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1578                                                   "SELECT * FROM %s",
1579                                                   fmtQualifiedId(fout->remoteVersion,
1580                                                                                  tbinfo->dobj.namespace->dobj.name,
1581                                                                                  classname));
1582         }
1583         if (tdinfo->filtercond)
1584                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1585
1586         ExecuteSqlStatement(fout, q->data);
1587
1588         while (1)
1589         {
1590                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1591                                                           PGRES_TUPLES_OK);
1592                 nfields = PQnfields(res);
1593                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1594                 {
1595                         /*
1596                          * First time through, we build as much of the INSERT statement as
1597                          * possible in "insertStmt", which we can then just print for each
1598                          * line. If the table happens to have zero columns then this will
1599                          * be a complete statement, otherwise it will end in "VALUES(" and
1600                          * be ready to have the row's column values appended.
1601                          */
1602                         if (insertStmt == NULL)
1603                         {
1604                                 insertStmt = createPQExpBuffer();
1605                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1606                                                                   fmtId(classname));
1607
1608                                 /* corner case for zero-column table */
1609                                 if (nfields == 0)
1610                                 {
1611                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1612                                 }
1613                                 else
1614                                 {
1615                                         /* append the list of column names if required */
1616                                         if (column_inserts)
1617                                         {
1618                                                 appendPQExpBufferStr(insertStmt, "(");
1619                                                 for (field = 0; field < nfields; field++)
1620                                                 {
1621                                                         if (field > 0)
1622                                                                 appendPQExpBufferStr(insertStmt, ", ");
1623                                                         appendPQExpBufferStr(insertStmt,
1624                                                                                                  fmtId(PQfname(res, field)));
1625                                                 }
1626                                                 appendPQExpBufferStr(insertStmt, ") ");
1627                                         }
1628
1629                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1630                                 }
1631                         }
1632
1633                         archputs(insertStmt->data, fout);
1634
1635                         /* if it is zero-column table then we're done */
1636                         if (nfields == 0)
1637                                 continue;
1638
1639                         for (field = 0; field < nfields; field++)
1640                         {
1641                                 if (field > 0)
1642                                         archputs(", ", fout);
1643                                 if (PQgetisnull(res, tuple, field))
1644                                 {
1645                                         archputs("NULL", fout);
1646                                         continue;
1647                                 }
1648
1649                                 /* XXX This code is partially duplicated in ruleutils.c */
1650                                 switch (PQftype(res, field))
1651                                 {
1652                                         case INT2OID:
1653                                         case INT4OID:
1654                                         case INT8OID:
1655                                         case OIDOID:
1656                                         case FLOAT4OID:
1657                                         case FLOAT8OID:
1658                                         case NUMERICOID:
1659                                                 {
1660                                                         /*
1661                                                          * These types are printed without quotes unless
1662                                                          * they contain values that aren't accepted by the
1663                                                          * scanner unquoted (e.g., 'NaN').      Note that
1664                                                          * strtod() and friends might accept NaN, so we
1665                                                          * can't use that to test.
1666                                                          *
1667                                                          * In reality we only need to defend against
1668                                                          * infinity and NaN, so we need not get too crazy
1669                                                          * about pattern matching here.
1670                                                          */
1671                                                         const char *s = PQgetvalue(res, tuple, field);
1672
1673                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1674                                                                 archputs(s, fout);
1675                                                         else
1676                                                                 archprintf(fout, "'%s'", s);
1677                                                 }
1678                                                 break;
1679
1680                                         case BITOID:
1681                                         case VARBITOID:
1682                                                 archprintf(fout, "B'%s'",
1683                                                                    PQgetvalue(res, tuple, field));
1684                                                 break;
1685
1686                                         case BOOLOID:
1687                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1688                                                         archputs("true", fout);
1689                                                 else
1690                                                         archputs("false", fout);
1691                                                 break;
1692
1693                                         default:
1694                                                 /* All other types are printed as string literals. */
1695                                                 resetPQExpBuffer(q);
1696                                                 appendStringLiteralAH(q,
1697                                                                                           PQgetvalue(res, tuple, field),
1698                                                                                           fout);
1699                                                 archputs(q->data, fout);
1700                                                 break;
1701                                 }
1702                         }
1703                         archputs(");\n", fout);
1704                 }
1705
1706                 if (PQntuples(res) <= 0)
1707                 {
1708                         PQclear(res);
1709                         break;
1710                 }
1711                 PQclear(res);
1712         }
1713
1714         archputs("\n\n", fout);
1715
1716         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1717
1718         destroyPQExpBuffer(q);
1719         if (insertStmt != NULL)
1720                 destroyPQExpBuffer(insertStmt);
1721
1722         return 1;
1723 }
1724
1725
1726 /*
1727  * dumpTableData -
1728  *        dump the contents of a single table
1729  *
1730  * Actually, this just makes an ArchiveEntry for the table contents.
1731  */
1732 static void
1733 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1734 {
1735         TableInfo  *tbinfo = tdinfo->tdtable;
1736         PQExpBuffer copyBuf = createPQExpBuffer();
1737         PQExpBuffer clistBuf = createPQExpBuffer();
1738         DataDumperPtr dumpFn;
1739         char       *copyStmt;
1740
1741         if (!dump_inserts)
1742         {
1743                 /* Dump/restore using COPY */
1744                 dumpFn = dumpTableData_copy;
1745                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1746                 appendPQExpBuffer(copyBuf, "COPY %s ",
1747                                                   fmtId(tbinfo->dobj.name));
1748                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1749                                                   fmtCopyColumnList(tbinfo, clistBuf),
1750                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1751                 copyStmt = copyBuf->data;
1752         }
1753         else
1754         {
1755                 /* Restore using INSERT */
1756                 dumpFn = dumpTableData_insert;
1757                 copyStmt = NULL;
1758         }
1759
1760         /*
1761          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1762          * dependency on its table as "special" and pass it to ArchiveEntry now.
1763          * See comments for BuildArchiveDependencies.
1764          */
1765         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1766                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1767                                  NULL, tbinfo->rolname,
1768                                  false, "TABLE DATA", SECTION_DATA,
1769                                  "", "", copyStmt,
1770                                  &(tbinfo->dobj.dumpId), 1,
1771                                  dumpFn, tdinfo);
1772
1773         destroyPQExpBuffer(copyBuf);
1774         destroyPQExpBuffer(clistBuf);
1775 }
1776
1777 /*
1778  * refreshMatViewData -
1779  *        load or refresh the contents of a single materialized view
1780  *
1781  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1782  * statement.
1783  */
1784 static void
1785 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1786 {
1787         TableInfo  *tbinfo = tdinfo->tdtable;
1788         PQExpBuffer q;
1789
1790         /* If the materialized view is not flagged as populated, skip this. */
1791         if (!tbinfo->relispopulated)
1792                 return;
1793
1794         q = createPQExpBuffer();
1795
1796         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1797                                           fmtId(tbinfo->dobj.name));
1798
1799         ArchiveEntry(fout,
1800                                  tdinfo->dobj.catId,    /* catalog ID */
1801                                  tdinfo->dobj.dumpId,   /* dump ID */
1802                                  tbinfo->dobj.name,             /* Name */
1803                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1804                                  NULL,                  /* Tablespace */
1805                                  tbinfo->rolname,               /* Owner */
1806                                  false,                 /* with oids */
1807                                  "MATERIALIZED VIEW DATA",              /* Desc */
1808                                  SECTION_POST_DATA,             /* Section */
1809                                  q->data,               /* Create */
1810                                  "",                    /* Del */
1811                                  NULL,                  /* Copy */
1812                                  tdinfo->dobj.dependencies,             /* Deps */
1813                                  tdinfo->dobj.nDeps,    /* # Deps */
1814                                  NULL,                  /* Dumper */
1815                                  NULL);                 /* Dumper Arg */
1816
1817         destroyPQExpBuffer(q);
1818 }
1819
1820 /*
1821  * getTableData -
1822  *        set up dumpable objects representing the contents of tables
1823  */
1824 static void
1825 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1826 {
1827         int                     i;
1828
1829         for (i = 0; i < numTables; i++)
1830         {
1831                 if (tblinfo[i].dobj.dump)
1832                         makeTableDataInfo(&(tblinfo[i]), oids);
1833         }
1834 }
1835
1836 /*
1837  * Make a dumpable object for the data of this specific table
1838  *
1839  * Note: we make a TableDataInfo if and only if we are going to dump the
1840  * table data; the "dump" flag in such objects isn't used.
1841  */
1842 static void
1843 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1844 {
1845         TableDataInfo *tdinfo;
1846
1847         /*
1848          * Nothing to do if we already decided to dump the table.  This will
1849          * happen for "config" tables.
1850          */
1851         if (tbinfo->dataObj != NULL)
1852                 return;
1853
1854         /* Skip VIEWs (no data to dump) */
1855         if (tbinfo->relkind == RELKIND_VIEW)
1856                 return;
1857         /* Skip FOREIGN TABLEs (no data to dump) */
1858         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1859                 return;
1860
1861         /* Don't dump data in unlogged tables, if so requested */
1862         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1863                 no_unlogged_table_data)
1864                 return;
1865
1866         /* Check that the data is not explicitly excluded */
1867         if (simple_oid_list_member(&tabledata_exclude_oids,
1868                                                            tbinfo->dobj.catId.oid))
1869                 return;
1870
1871         /* OK, let's dump it */
1872         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1873
1874         if (tbinfo->relkind == RELKIND_MATVIEW)
1875                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1876         else
1877                 tdinfo->dobj.objType = DO_TABLE_DATA;
1878
1879         /*
1880          * Note: use tableoid 0 so that this object won't be mistaken for
1881          * something that pg_depend entries apply to.
1882          */
1883         tdinfo->dobj.catId.tableoid = 0;
1884         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1885         AssignDumpId(&tdinfo->dobj);
1886         tdinfo->dobj.name = tbinfo->dobj.name;
1887         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1888         tdinfo->tdtable = tbinfo;
1889         tdinfo->oids = oids;
1890         tdinfo->filtercond = NULL;      /* might get set later */
1891         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1892
1893         tbinfo->dataObj = tdinfo;
1894 }
1895
1896 /*
1897  * The refresh for a materialized view must be dependent on the refresh for
1898  * any materialized view that this one is dependent on.
1899  *
1900  * This must be called after all the objects are created, but before they are
1901  * sorted.
1902  */
1903 static void
1904 buildMatViewRefreshDependencies(Archive *fout)
1905 {
1906         PQExpBuffer query;
1907         PGresult   *res;
1908         int                     ntups,
1909                                 i;
1910         int                     i_classid,
1911                                 i_objid,
1912                                 i_refobjid;
1913
1914         /* No Mat Views before 9.3. */
1915         if (fout->remoteVersion < 90300)
1916                 return;
1917
1918         /* Make sure we are in proper schema */
1919         selectSourceSchema(fout, "pg_catalog");
1920
1921         query = createPQExpBuffer();
1922
1923         appendPQExpBuffer(query, "with recursive w as "
1924                                           "( "
1925                                         "select d1.objid, d2.refobjid, c2.relkind as refrelkind "
1926                                           "from pg_depend d1 "
1927                                           "join pg_class c1 on c1.oid = d1.objid "
1928                                           "and c1.relkind = 'm' "
1929                                           "join pg_rewrite r1 on r1.ev_class = d1.objid "
1930                                   "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass "
1931                                           "and d2.objid = r1.oid "
1932                                           "and d2.refobjid <> d1.objid "
1933                                           "join pg_class c2 on c2.oid = d2.refobjid "
1934                                           "and c2.relkind in ('m','v') "
1935                                           "where d1.classid = 'pg_class'::regclass "
1936                                           "union "
1937                                           "select w.objid, d3.refobjid, c3.relkind "
1938                                           "from w "
1939                                           "join pg_rewrite r3 on r3.ev_class = w.refobjid "
1940                                   "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass "
1941                                           "and d3.objid = r3.oid "
1942                                           "and d3.refobjid <> w.refobjid "
1943                                           "join pg_class c3 on c3.oid = d3.refobjid "
1944                                           "and c3.relkind in ('m','v') "
1945                                           ") "
1946                           "select 'pg_class'::regclass::oid as classid, objid, refobjid "
1947                                           "from w "
1948                                           "where refrelkind = 'm'");
1949
1950         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1951
1952         ntups = PQntuples(res);
1953
1954         i_classid = PQfnumber(res, "classid");
1955         i_objid = PQfnumber(res, "objid");
1956         i_refobjid = PQfnumber(res, "refobjid");
1957
1958         for (i = 0; i < ntups; i++)
1959         {
1960                 CatalogId       objId;
1961                 CatalogId       refobjId;
1962                 DumpableObject *dobj;
1963                 DumpableObject *refdobj;
1964                 TableInfo  *tbinfo;
1965                 TableInfo  *reftbinfo;
1966
1967                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1968                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1969                 refobjId.tableoid = objId.tableoid;
1970                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1971
1972                 dobj = findObjectByCatalogId(objId);
1973                 if (dobj == NULL)
1974                         continue;
1975
1976                 Assert(dobj->objType == DO_TABLE);
1977                 tbinfo = (TableInfo *) dobj;
1978                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1979                 dobj = (DumpableObject *) tbinfo->dataObj;
1980                 if (dobj == NULL)
1981                         continue;
1982                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
1983
1984                 refdobj = findObjectByCatalogId(refobjId);
1985                 if (refdobj == NULL)
1986                         continue;
1987
1988                 Assert(refdobj->objType == DO_TABLE);
1989                 reftbinfo = (TableInfo *) refdobj;
1990                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
1991                 refdobj = (DumpableObject *) reftbinfo->dataObj;
1992                 if (refdobj == NULL)
1993                         continue;
1994                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
1995
1996                 addObjectDependency(dobj, refdobj->dumpId);
1997
1998                 if (!reftbinfo->relispopulated)
1999                         tbinfo->relispopulated = false;
2000         }
2001
2002         PQclear(res);
2003
2004         destroyPQExpBuffer(query);
2005 }
2006
2007 /*
2008  * getTableDataFKConstraints -
2009  *        add dump-order dependencies reflecting foreign key constraints
2010  *
2011  * This code is executed only in a data-only dump --- in schema+data dumps
2012  * we handle foreign key issues by not creating the FK constraints until
2013  * after the data is loaded.  In a data-only dump, however, we want to
2014  * order the table data objects in such a way that a table's referenced
2015  * tables are restored first.  (In the presence of circular references or
2016  * self-references this may be impossible; we'll detect and complain about
2017  * that during the dependency sorting step.)
2018  */
2019 static void
2020 getTableDataFKConstraints(void)
2021 {
2022         DumpableObject **dobjs;
2023         int                     numObjs;
2024         int                     i;
2025
2026         /* Search through all the dumpable objects for FK constraints */
2027         getDumpableObjects(&dobjs, &numObjs);
2028         for (i = 0; i < numObjs; i++)
2029         {
2030                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2031                 {
2032                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2033                         TableInfo  *ftable;
2034
2035                         /* Not interesting unless both tables are to be dumped */
2036                         if (cinfo->contable == NULL ||
2037                                 cinfo->contable->dataObj == NULL)
2038                                 continue;
2039                         ftable = findTableByOid(cinfo->confrelid);
2040                         if (ftable == NULL ||
2041                                 ftable->dataObj == NULL)
2042                                 continue;
2043
2044                         /*
2045                          * Okay, make referencing table's TABLE_DATA object depend on the
2046                          * referenced table's TABLE_DATA object.
2047                          */
2048                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2049                                                                 ftable->dataObj->dobj.dumpId);
2050                 }
2051         }
2052         free(dobjs);
2053 }
2054
2055
2056 /*
2057  * guessConstraintInheritance:
2058  *      In pre-8.4 databases, we can't tell for certain which constraints
2059  *      are inherited.  We assume a CHECK constraint is inherited if its name
2060  *      matches the name of any constraint in the parent.  Originally this code
2061  *      tried to compare the expression texts, but that can fail for various
2062  *      reasons --- for example, if the parent and child tables are in different
2063  *      schemas, reverse-listing of function calls may produce different text
2064  *      (schema-qualified or not) depending on search path.
2065  *
2066  *      In 8.4 and up we can rely on the conislocal field to decide which
2067  *      constraints must be dumped; much safer.
2068  *
2069  *      This function assumes all conislocal flags were initialized to TRUE.
2070  *      It clears the flag on anything that seems to be inherited.
2071  */
2072 static void
2073 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2074 {
2075         int                     i,
2076                                 j,
2077                                 k;
2078
2079         for (i = 0; i < numTables; i++)
2080         {
2081                 TableInfo  *tbinfo = &(tblinfo[i]);
2082                 int                     numParents;
2083                 TableInfo **parents;
2084                 TableInfo  *parent;
2085
2086                 /* Sequences and views never have parents */
2087                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2088                         tbinfo->relkind == RELKIND_VIEW)
2089                         continue;
2090
2091                 /* Don't bother computing anything for non-target tables, either */
2092                 if (!tbinfo->dobj.dump)
2093                         continue;
2094
2095                 numParents = tbinfo->numParents;
2096                 parents = tbinfo->parents;
2097
2098                 if (numParents == 0)
2099                         continue;                       /* nothing to see here, move along */
2100
2101                 /* scan for inherited CHECK constraints */
2102                 for (j = 0; j < tbinfo->ncheck; j++)
2103                 {
2104                         ConstraintInfo *constr;
2105
2106                         constr = &(tbinfo->checkexprs[j]);
2107
2108                         for (k = 0; k < numParents; k++)
2109                         {
2110                                 int                     l;
2111
2112                                 parent = parents[k];
2113                                 for (l = 0; l < parent->ncheck; l++)
2114                                 {
2115                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2116
2117                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2118                                         {
2119                                                 constr->conislocal = false;
2120                                                 break;
2121                                         }
2122                                 }
2123                                 if (!constr->conislocal)
2124                                         break;
2125                         }
2126                 }
2127         }
2128 }
2129
2130
2131 /*
2132  * dumpDatabase:
2133  *      dump the database definition
2134  */
2135 static void
2136 dumpDatabase(Archive *fout)
2137 {
2138         PQExpBuffer dbQry = createPQExpBuffer();
2139         PQExpBuffer delQry = createPQExpBuffer();
2140         PQExpBuffer creaQry = createPQExpBuffer();
2141         PGconn     *conn = GetConnection(fout);
2142         PGresult   *res;
2143         int                     i_tableoid,
2144                                 i_oid,
2145                                 i_dba,
2146                                 i_encoding,
2147                                 i_collate,
2148                                 i_ctype,
2149                                 i_frozenxid,
2150                                 i_tablespace;
2151         CatalogId       dbCatId;
2152         DumpId          dbDumpId;
2153         const char *datname,
2154                            *dba,
2155                            *encoding,
2156                            *collate,
2157                            *ctype,
2158                            *tablespace;
2159         uint32          frozenxid;
2160
2161         datname = PQdb(conn);
2162
2163         if (g_verbose)
2164                 write_msg(NULL, "saving database definition\n");
2165
2166         /* Make sure we are in proper schema */
2167         selectSourceSchema(fout, "pg_catalog");
2168
2169         /* Get the database owner and parameters from pg_database */
2170         if (fout->remoteVersion >= 80400)
2171         {
2172                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2173                                                   "(%s datdba) AS dba, "
2174                                                   "pg_encoding_to_char(encoding) AS encoding, "
2175                                                   "datcollate, datctype, datfrozenxid, "
2176                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2177                                           "shobj_description(oid, 'pg_database') AS description "
2178
2179                                                   "FROM pg_database "
2180                                                   "WHERE datname = ",
2181                                                   username_subquery);
2182                 appendStringLiteralAH(dbQry, datname, fout);
2183         }
2184         else if (fout->remoteVersion >= 80200)
2185         {
2186                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2187                                                   "(%s datdba) AS dba, "
2188                                                   "pg_encoding_to_char(encoding) AS encoding, "
2189                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2190                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2191                                           "shobj_description(oid, 'pg_database') AS description "
2192
2193                                                   "FROM pg_database "
2194                                                   "WHERE datname = ",
2195                                                   username_subquery);
2196                 appendStringLiteralAH(dbQry, datname, fout);
2197         }
2198         else if (fout->remoteVersion >= 80000)
2199         {
2200                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2201                                                   "(%s datdba) AS dba, "
2202                                                   "pg_encoding_to_char(encoding) AS encoding, "
2203                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2204                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2205                                                   "FROM pg_database "
2206                                                   "WHERE datname = ",
2207                                                   username_subquery);
2208                 appendStringLiteralAH(dbQry, datname, fout);
2209         }
2210         else if (fout->remoteVersion >= 70100)
2211         {
2212                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2213                                                   "(%s datdba) AS dba, "
2214                                                   "pg_encoding_to_char(encoding) AS encoding, "
2215                                                   "NULL AS datcollate, NULL AS datctype, "
2216                                                   "0 AS datfrozenxid, "
2217                                                   "NULL AS tablespace "
2218                                                   "FROM pg_database "
2219                                                   "WHERE datname = ",
2220                                                   username_subquery);
2221                 appendStringLiteralAH(dbQry, datname, fout);
2222         }
2223         else
2224         {
2225                 appendPQExpBuffer(dbQry, "SELECT "
2226                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2227                                                   "oid, "
2228                                                   "(%s datdba) AS dba, "
2229                                                   "pg_encoding_to_char(encoding) AS encoding, "
2230                                                   "NULL AS datcollate, NULL AS datctype, "
2231                                                   "0 AS datfrozenxid, "
2232                                                   "NULL AS tablespace "
2233                                                   "FROM pg_database "
2234                                                   "WHERE datname = ",
2235                                                   username_subquery);
2236                 appendStringLiteralAH(dbQry, datname, fout);
2237         }
2238
2239         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2240
2241         i_tableoid = PQfnumber(res, "tableoid");
2242         i_oid = PQfnumber(res, "oid");
2243         i_dba = PQfnumber(res, "dba");
2244         i_encoding = PQfnumber(res, "encoding");
2245         i_collate = PQfnumber(res, "datcollate");
2246         i_ctype = PQfnumber(res, "datctype");
2247         i_frozenxid = PQfnumber(res, "datfrozenxid");
2248         i_tablespace = PQfnumber(res, "tablespace");
2249
2250         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2251         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2252         dba = PQgetvalue(res, 0, i_dba);
2253         encoding = PQgetvalue(res, 0, i_encoding);
2254         collate = PQgetvalue(res, 0, i_collate);
2255         ctype = PQgetvalue(res, 0, i_ctype);
2256         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2257         tablespace = PQgetvalue(res, 0, i_tablespace);
2258
2259         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2260                                           fmtId(datname));
2261         if (strlen(encoding) > 0)
2262         {
2263                 appendPQExpBuffer(creaQry, " ENCODING = ");
2264                 appendStringLiteralAH(creaQry, encoding, fout);
2265         }
2266         if (strlen(collate) > 0)
2267         {
2268                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
2269                 appendStringLiteralAH(creaQry, collate, fout);
2270         }
2271         if (strlen(ctype) > 0)
2272         {
2273                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
2274                 appendStringLiteralAH(creaQry, ctype, fout);
2275         }
2276         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2277                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2278                                                   fmtId(tablespace));
2279         appendPQExpBuffer(creaQry, ";\n");
2280
2281         if (binary_upgrade)
2282         {
2283                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
2284                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2285                                                   "SET datfrozenxid = '%u'\n"
2286                                                   "WHERE        datname = ",
2287                                                   frozenxid);
2288                 appendStringLiteralAH(creaQry, datname, fout);
2289                 appendPQExpBuffer(creaQry, ";\n");
2290
2291         }
2292
2293         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2294                                           fmtId(datname));
2295
2296         dbDumpId = createDumpId();
2297
2298         ArchiveEntry(fout,
2299                                  dbCatId,               /* catalog ID */
2300                                  dbDumpId,              /* dump ID */
2301                                  datname,               /* Name */
2302                                  NULL,                  /* Namespace */
2303                                  NULL,                  /* Tablespace */
2304                                  dba,                   /* Owner */
2305                                  false,                 /* with oids */
2306                                  "DATABASE",    /* Desc */
2307                                  SECTION_PRE_DATA,              /* Section */
2308                                  creaQry->data, /* Create */
2309                                  delQry->data,  /* Del */
2310                                  NULL,                  /* Copy */
2311                                  NULL,                  /* Deps */
2312                                  0,                             /* # Deps */
2313                                  NULL,                  /* Dumper */
2314                                  NULL);                 /* Dumper Arg */
2315
2316         /*
2317          * pg_largeobject and pg_largeobject_metadata come from the old system
2318          * intact, so set their relfrozenxids.
2319          */
2320         if (binary_upgrade)
2321         {
2322                 PGresult   *lo_res;
2323                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2324                 PQExpBuffer loOutQry = createPQExpBuffer();
2325                 int                     i_relfrozenxid;
2326
2327                 /*
2328                  * pg_largeobject
2329                  */
2330                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2331                                                   "FROM pg_catalog.pg_class\n"
2332                                                   "WHERE oid = %u;\n",
2333                                                   LargeObjectRelationId);
2334
2335                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2336
2337                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2338
2339                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2340                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2341                                                   "SET relfrozenxid = '%u'\n"
2342                                                   "WHERE oid = %u;\n",
2343                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2344                                                   LargeObjectRelationId);
2345                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2346                                          "pg_largeobject", NULL, NULL, "",
2347                                          false, "pg_largeobject", SECTION_PRE_DATA,
2348                                          loOutQry->data, "", NULL,
2349                                          NULL, 0,
2350                                          NULL, NULL);
2351
2352                 PQclear(lo_res);
2353
2354                 /*
2355                  * pg_largeobject_metadata
2356                  */
2357                 if (fout->remoteVersion >= 90000)
2358                 {
2359                         resetPQExpBuffer(loFrozenQry);
2360                         resetPQExpBuffer(loOutQry);
2361
2362                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2363                                                           "FROM pg_catalog.pg_class\n"
2364                                                           "WHERE oid = %u;\n",
2365                                                           LargeObjectMetadataRelationId);
2366
2367                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2368
2369                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2370
2371                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2372                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2373                                                           "SET relfrozenxid = '%u'\n"
2374                                                           "WHERE oid = %u;\n",
2375                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2376                                                           LargeObjectMetadataRelationId);
2377                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2378                                                  "pg_largeobject_metadata", NULL, NULL, "",
2379                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2380                                                  loOutQry->data, "", NULL,
2381                                                  NULL, 0,
2382                                                  NULL, NULL);
2383
2384                         PQclear(lo_res);
2385                 }
2386
2387                 destroyPQExpBuffer(loFrozenQry);
2388                 destroyPQExpBuffer(loOutQry);
2389         }
2390
2391         /* Dump DB comment if any */
2392         if (fout->remoteVersion >= 80200)
2393         {
2394                 /*
2395                  * 8.2 keeps comments on shared objects in a shared table, so we
2396                  * cannot use the dumpComment used for other database objects.
2397                  */
2398                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2399
2400                 if (comment && strlen(comment))
2401                 {
2402                         resetPQExpBuffer(dbQry);
2403
2404                         /*
2405                          * Generates warning when loaded into a differently-named
2406                          * database.
2407                          */
2408                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2409                         appendStringLiteralAH(dbQry, comment, fout);
2410                         appendPQExpBuffer(dbQry, ";\n");
2411
2412                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2413                                                  dba, false, "COMMENT", SECTION_NONE,
2414                                                  dbQry->data, "", NULL,
2415                                                  &dbDumpId, 1, NULL, NULL);
2416                 }
2417         }
2418         else
2419         {
2420                 resetPQExpBuffer(dbQry);
2421                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2422                 dumpComment(fout, dbQry->data, NULL, "",
2423                                         dbCatId, 0, dbDumpId);
2424         }
2425
2426         PQclear(res);
2427
2428         /* Dump shared security label. */
2429         if (!no_security_labels && fout->remoteVersion >= 90200)
2430         {
2431                 PQExpBuffer seclabelQry = createPQExpBuffer();
2432
2433                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2434                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2435                 resetPQExpBuffer(seclabelQry);
2436                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2437                 if (strlen(seclabelQry->data))
2438                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2439                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2440                                                  seclabelQry->data, "", NULL,
2441                                                  &dbDumpId, 1, NULL, NULL);
2442                 destroyPQExpBuffer(seclabelQry);
2443         }
2444
2445         destroyPQExpBuffer(dbQry);
2446         destroyPQExpBuffer(delQry);
2447         destroyPQExpBuffer(creaQry);
2448 }
2449
2450
2451 /*
2452  * dumpEncoding: put the correct encoding into the archive
2453  */
2454 static void
2455 dumpEncoding(Archive *AH)
2456 {
2457         const char *encname = pg_encoding_to_char(AH->encoding);
2458         PQExpBuffer qry = createPQExpBuffer();
2459
2460         if (g_verbose)
2461                 write_msg(NULL, "saving encoding = %s\n", encname);
2462
2463         appendPQExpBuffer(qry, "SET client_encoding = ");
2464         appendStringLiteralAH(qry, encname, AH);
2465         appendPQExpBuffer(qry, ";\n");
2466
2467         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2468                                  "ENCODING", NULL, NULL, "",
2469                                  false, "ENCODING", SECTION_PRE_DATA,
2470                                  qry->data, "", NULL,
2471                                  NULL, 0,
2472                                  NULL, NULL);
2473
2474         destroyPQExpBuffer(qry);
2475 }
2476
2477
2478 /*
2479  * dumpStdStrings: put the correct escape string behavior into the archive
2480  */
2481 static void
2482 dumpStdStrings(Archive *AH)
2483 {
2484         const char *stdstrings = AH->std_strings ? "on" : "off";
2485         PQExpBuffer qry = createPQExpBuffer();
2486
2487         if (g_verbose)
2488                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2489                                   stdstrings);
2490
2491         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2492                                           stdstrings);
2493
2494         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2495                                  "STDSTRINGS", NULL, NULL, "",
2496                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2497                                  qry->data, "", NULL,
2498                                  NULL, 0,
2499                                  NULL, NULL);
2500
2501         destroyPQExpBuffer(qry);
2502 }
2503
2504
2505 /*
2506  * getBlobs:
2507  *      Collect schema-level data about large objects
2508  */
2509 static void
2510 getBlobs(Archive *fout)
2511 {
2512         PQExpBuffer blobQry = createPQExpBuffer();
2513         BlobInfo   *binfo;
2514         DumpableObject *bdata;
2515         PGresult   *res;
2516         int                     ntups;
2517         int                     i;
2518
2519         /* Verbose message */
2520         if (g_verbose)
2521                 write_msg(NULL, "reading large objects\n");
2522
2523         /* Make sure we are in proper schema */
2524         selectSourceSchema(fout, "pg_catalog");
2525
2526         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2527         if (fout->remoteVersion >= 90000)
2528                 appendPQExpBuffer(blobQry,
2529                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2530                                                   " FROM pg_largeobject_metadata",
2531                                                   username_subquery);
2532         else if (fout->remoteVersion >= 70100)
2533                 appendPQExpBuffer(blobQry,
2534                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2535                                                   " FROM pg_largeobject");
2536         else
2537                 appendPQExpBuffer(blobQry,
2538                                                   "SELECT oid, NULL::oid, NULL::oid"
2539                                                   " FROM pg_class WHERE relkind = 'l'");
2540
2541         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2542
2543         ntups = PQntuples(res);
2544         if (ntups > 0)
2545         {
2546                 /*
2547                  * Each large object has its own BLOB archive entry.
2548                  */
2549                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2550
2551                 for (i = 0; i < ntups; i++)
2552                 {
2553                         binfo[i].dobj.objType = DO_BLOB;
2554                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2555                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2556                         AssignDumpId(&binfo[i].dobj);
2557
2558                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2559                         if (!PQgetisnull(res, i, 1))
2560                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2561                         else
2562                                 binfo[i].rolname = "";
2563                         if (!PQgetisnull(res, i, 2))
2564                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2565                         else
2566                                 binfo[i].blobacl = NULL;
2567                 }
2568
2569                 /*
2570                  * If we have any large objects, a "BLOBS" archive entry is needed.
2571                  * This is just a placeholder for sorting; it carries no data now.
2572                  */
2573                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2574                 bdata->objType = DO_BLOB_DATA;
2575                 bdata->catId = nilCatalogId;
2576                 AssignDumpId(bdata);
2577                 bdata->name = pg_strdup("BLOBS");
2578         }
2579
2580         PQclear(res);
2581         destroyPQExpBuffer(blobQry);
2582 }
2583
2584 /*
2585  * dumpBlob
2586  *
2587  * dump the definition (metadata) of the given large object
2588  */
2589 static void
2590 dumpBlob(Archive *fout, BlobInfo *binfo)
2591 {
2592         PQExpBuffer cquery = createPQExpBuffer();
2593         PQExpBuffer dquery = createPQExpBuffer();
2594
2595         appendPQExpBuffer(cquery,
2596                                           "SELECT pg_catalog.lo_create('%s');\n",
2597                                           binfo->dobj.name);
2598
2599         appendPQExpBuffer(dquery,
2600                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2601                                           binfo->dobj.name);
2602
2603         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2604                                  binfo->dobj.name,
2605                                  NULL, NULL,
2606                                  binfo->rolname, false,
2607                                  "BLOB", SECTION_PRE_DATA,
2608                                  cquery->data, dquery->data, NULL,
2609                                  NULL, 0,
2610                                  NULL, NULL);
2611
2612         /* set up tag for comment and/or ACL */
2613         resetPQExpBuffer(cquery);
2614         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2615
2616         /* Dump comment if any */
2617         dumpComment(fout, cquery->data,
2618                                 NULL, binfo->rolname,
2619                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2620
2621         /* Dump security label if any */
2622         dumpSecLabel(fout, cquery->data,
2623                                  NULL, binfo->rolname,
2624                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2625
2626         /* Dump ACL if any */
2627         if (binfo->blobacl)
2628                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2629                                 binfo->dobj.name, NULL, cquery->data,
2630                                 NULL, binfo->rolname, binfo->blobacl);
2631
2632         destroyPQExpBuffer(cquery);
2633         destroyPQExpBuffer(dquery);
2634 }
2635
2636 /*
2637  * dumpBlobs:
2638  *      dump the data contents of all large objects
2639  */
2640 static int
2641 dumpBlobs(Archive *fout, void *arg)
2642 {
2643         const char *blobQry;
2644         const char *blobFetchQry;
2645         PGconn     *conn = GetConnection(fout);
2646         PGresult   *res;
2647         char            buf[LOBBUFSIZE];
2648         int                     ntups;
2649         int                     i;
2650         int                     cnt;
2651
2652         if (g_verbose)
2653                 write_msg(NULL, "saving large objects\n");
2654
2655         /* Make sure we are in proper schema */
2656         selectSourceSchema(fout, "pg_catalog");
2657
2658         /*
2659          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2660          * the already-in-memory dumpable objects instead...
2661          */
2662         if (fout->remoteVersion >= 90000)
2663                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2664         else if (fout->remoteVersion >= 70100)
2665                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2666         else
2667                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2668
2669         ExecuteSqlStatement(fout, blobQry);
2670
2671         /* Command to fetch from cursor */
2672         blobFetchQry = "FETCH 1000 IN bloboid";
2673
2674         do
2675         {
2676                 /* Do a fetch */
2677                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2678
2679                 /* Process the tuples, if any */
2680                 ntups = PQntuples(res);
2681                 for (i = 0; i < ntups; i++)
2682                 {
2683                         Oid                     blobOid;
2684                         int                     loFd;
2685
2686                         blobOid = atooid(PQgetvalue(res, i, 0));
2687                         /* Open the BLOB */
2688                         loFd = lo_open(conn, blobOid, INV_READ);
2689                         if (loFd == -1)
2690                                 exit_horribly(NULL, "could not open large object %u: %s",
2691                                                           blobOid, PQerrorMessage(conn));
2692
2693                         StartBlob(fout, blobOid);
2694
2695                         /* Now read it in chunks, sending data to archive */
2696                         do
2697                         {
2698                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2699                                 if (cnt < 0)
2700                                         exit_horribly(NULL, "error reading large object %u: %s",
2701                                                                   blobOid, PQerrorMessage(conn));
2702
2703                                 WriteData(fout, buf, cnt);
2704                         } while (cnt > 0);
2705
2706                         lo_close(conn, loFd);
2707
2708                         EndBlob(fout, blobOid);
2709                 }
2710
2711                 PQclear(res);
2712         } while (ntups > 0);
2713
2714         return 1;
2715 }
2716
2717 static void
2718 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2719                                                                                  PQExpBuffer upgrade_buffer,
2720                                                                                  Oid pg_type_oid)
2721 {
2722         PQExpBuffer upgrade_query = createPQExpBuffer();
2723         PGresult   *upgrade_res;
2724         Oid                     pg_type_array_oid;
2725
2726         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2727         appendPQExpBuffer(upgrade_buffer,
2728          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2729                                           pg_type_oid);
2730
2731         /* we only support old >= 8.3 for binary upgrades */
2732         appendPQExpBuffer(upgrade_query,
2733                                           "SELECT typarray "
2734                                           "FROM pg_catalog.pg_type "
2735                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2736                                           pg_type_oid);
2737
2738         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2739
2740         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2741
2742         if (OidIsValid(pg_type_array_oid))
2743         {
2744                 appendPQExpBuffer(upgrade_buffer,
2745                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2746                 appendPQExpBuffer(upgrade_buffer,
2747                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2748                                                   pg_type_array_oid);
2749         }
2750
2751         PQclear(upgrade_res);
2752         destroyPQExpBuffer(upgrade_query);
2753 }
2754
2755 static bool
2756 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2757                                                                                 PQExpBuffer upgrade_buffer,
2758                                                                                 Oid pg_rel_oid)
2759 {
2760         PQExpBuffer upgrade_query = createPQExpBuffer();
2761         PGresult   *upgrade_res;
2762         Oid                     pg_type_oid;
2763         bool            toast_set = false;
2764
2765         /* we only support old >= 8.3 for binary upgrades */
2766         appendPQExpBuffer(upgrade_query,
2767                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2768                                           "FROM pg_catalog.pg_class c "
2769                                           "LEFT JOIN pg_catalog.pg_class t ON "
2770                                           "  (c.reltoastrelid = t.oid) "
2771                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2772                                           pg_rel_oid);
2773
2774         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2775
2776         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2777
2778         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2779                                                                                          pg_type_oid);
2780
2781         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2782         {
2783                 /* Toast tables do not have pg_type array rows */
2784                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2785                                                                                         PQfnumber(upgrade_res, "trel")));
2786
2787                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2788                 appendPQExpBuffer(upgrade_buffer,
2789                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2790                                                   pg_type_toast_oid);
2791
2792                 toast_set = true;
2793         }
2794
2795         PQclear(upgrade_res);
2796         destroyPQExpBuffer(upgrade_query);
2797
2798         return toast_set;
2799 }
2800
2801 static void
2802 binary_upgrade_set_pg_class_oids(Archive *fout,
2803                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2804                                                                  bool is_index)
2805 {
2806         PQExpBuffer upgrade_query = createPQExpBuffer();
2807         PGresult   *upgrade_res;
2808         Oid                     pg_class_reltoastrelid;
2809         Oid                     pg_index_indexrelid;
2810
2811         appendPQExpBuffer(upgrade_query,
2812                                           "SELECT c.reltoastrelid, i.indexrelid "
2813                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2814                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
2815                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2816                                           pg_class_oid);
2817
2818         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2819
2820         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2821         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
2822
2823         appendPQExpBuffer(upgrade_buffer,
2824                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2825
2826         if (!is_index)
2827         {
2828                 appendPQExpBuffer(upgrade_buffer,
2829                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2830                                                   pg_class_oid);
2831                 /* only tables have toast tables, not indexes */
2832                 if (OidIsValid(pg_class_reltoastrelid))
2833                 {
2834                         /*
2835                          * One complexity is that the table definition might not require
2836                          * the creation of a TOAST table, and the TOAST table might have
2837                          * been created long after table creation, when the table was
2838                          * loaded with wide data.  By setting the TOAST oid we force
2839                          * creation of the TOAST heap and TOAST index by the backend so we
2840                          * can cleanly copy the files during binary upgrade.
2841                          */
2842
2843                         appendPQExpBuffer(upgrade_buffer,
2844                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2845                                                           pg_class_reltoastrelid);
2846
2847                         /* every toast table has an index */
2848                         appendPQExpBuffer(upgrade_buffer,
2849                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2850                                                           pg_index_indexrelid);
2851                 }
2852         }
2853         else
2854                 appendPQExpBuffer(upgrade_buffer,
2855                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2856                                                   pg_class_oid);
2857
2858         appendPQExpBuffer(upgrade_buffer, "\n");
2859
2860         PQclear(upgrade_res);
2861         destroyPQExpBuffer(upgrade_query);
2862 }
2863
2864 /*
2865  * If the DumpableObject is a member of an extension, add a suitable
2866  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2867  */
2868 static void
2869 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2870                                                                 DumpableObject *dobj,
2871                                                                 const char *objlabel)
2872 {
2873         DumpableObject *extobj = NULL;
2874         int                     i;
2875
2876         if (!dobj->ext_member)
2877                 return;
2878
2879         /*
2880          * Find the parent extension.  We could avoid this search if we wanted to
2881          * add a link field to DumpableObject, but the space costs of that would
2882          * be considerable.  We assume that member objects could only have a
2883          * direct dependency on their own extension, not any others.
2884          */
2885         for (i = 0; i < dobj->nDeps; i++)
2886         {
2887                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2888                 if (extobj && extobj->objType == DO_EXTENSION)
2889                         break;
2890                 extobj = NULL;
2891         }
2892         if (extobj == NULL)
2893                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2894
2895         appendPQExpBuffer(upgrade_buffer,
2896           "\n-- For binary upgrade, handle extension membership the hard way\n");
2897         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2898                                           fmtId(extobj->name),
2899                                           objlabel);
2900 }
2901
2902 /*
2903  * getNamespaces:
2904  *        read all namespaces in the system catalogs and return them in the
2905  * NamespaceInfo* structure
2906  *
2907  *      numNamespaces is set to the number of namespaces read in
2908  */
2909 NamespaceInfo *
2910 getNamespaces(Archive *fout, int *numNamespaces)
2911 {
2912         PGresult   *res;
2913         int                     ntups;
2914         int                     i;
2915         PQExpBuffer query;
2916         NamespaceInfo *nsinfo;
2917         int                     i_tableoid;
2918         int                     i_oid;
2919         int                     i_nspname;
2920         int                     i_rolname;
2921         int                     i_nspacl;
2922
2923         /*
2924          * Before 7.3, there are no real namespaces; create two dummy entries, one
2925          * for user stuff and one for system stuff.
2926          */
2927         if (fout->remoteVersion < 70300)
2928         {
2929                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2930
2931                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2932                 nsinfo[0].dobj.catId.tableoid = 0;
2933                 nsinfo[0].dobj.catId.oid = 0;
2934                 AssignDumpId(&nsinfo[0].dobj);
2935                 nsinfo[0].dobj.name = pg_strdup("public");
2936                 nsinfo[0].rolname = pg_strdup("");
2937                 nsinfo[0].nspacl = pg_strdup("");
2938
2939                 selectDumpableNamespace(&nsinfo[0]);
2940
2941                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2942                 nsinfo[1].dobj.catId.tableoid = 0;
2943                 nsinfo[1].dobj.catId.oid = 1;
2944                 AssignDumpId(&nsinfo[1].dobj);
2945                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2946                 nsinfo[1].rolname = pg_strdup("");
2947                 nsinfo[1].nspacl = pg_strdup("");
2948
2949                 selectDumpableNamespace(&nsinfo[1]);
2950
2951                 *numNamespaces = 2;
2952
2953                 return nsinfo;
2954         }
2955
2956         query = createPQExpBuffer();
2957
2958         /* Make sure we are in proper schema */
2959         selectSourceSchema(fout, "pg_catalog");
2960
2961         /*
2962          * we fetch all namespaces including system ones, so that every object we
2963          * read in can be linked to a containing namespace.
2964          */
2965         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2966                                           "(%s nspowner) AS rolname, "
2967                                           "nspacl FROM pg_namespace",
2968                                           username_subquery);
2969
2970         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2971
2972         ntups = PQntuples(res);
2973
2974         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2975
2976         i_tableoid = PQfnumber(res, "tableoid");
2977         i_oid = PQfnumber(res, "oid");
2978         i_nspname = PQfnumber(res, "nspname");
2979         i_rolname = PQfnumber(res, "rolname");
2980         i_nspacl = PQfnumber(res, "nspacl");
2981
2982         for (i = 0; i < ntups; i++)
2983         {
2984                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2985                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2986                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2987                 AssignDumpId(&nsinfo[i].dobj);
2988                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2989                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2990                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2991
2992                 /* Decide whether to dump this namespace */
2993                 selectDumpableNamespace(&nsinfo[i]);
2994
2995                 if (strlen(nsinfo[i].rolname) == 0)
2996                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2997                                           nsinfo[i].dobj.name);
2998         }
2999
3000         PQclear(res);
3001         destroyPQExpBuffer(query);
3002
3003         *numNamespaces = ntups;
3004
3005         return nsinfo;
3006 }
3007
3008 /*
3009  * findNamespace:
3010  *              given a namespace OID and an object OID, look up the info read by
3011  *              getNamespaces
3012  *
3013  * NB: for pre-7.3 source database, we use object OID to guess whether it's
3014  * a system object or not.      In 7.3 and later there is no guessing, and we
3015  * don't use objoid at all.
3016  */
3017 static NamespaceInfo *
3018 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
3019 {
3020         NamespaceInfo *nsinfo;
3021
3022         if (fout->remoteVersion >= 70300)
3023         {
3024                 nsinfo = findNamespaceByOid(nsoid);
3025         }
3026         else
3027         {
3028                 /* This code depends on the dummy objects set up by getNamespaces. */
3029                 Oid                     i;
3030
3031                 if (objoid > g_last_builtin_oid)
3032                         i = 0;                          /* user object */
3033                 else
3034                         i = 1;                          /* system object */
3035                 nsinfo = findNamespaceByOid(i);
3036         }
3037
3038         if (nsinfo == NULL)
3039                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3040
3041         return nsinfo;
3042 }
3043
3044 /*
3045  * getExtensions:
3046  *        read all extensions in the system catalogs and return them in the
3047  * ExtensionInfo* structure
3048  *
3049  *      numExtensions is set to the number of extensions read in
3050  */
3051 ExtensionInfo *
3052 getExtensions(Archive *fout, int *numExtensions)
3053 {
3054         PGresult   *res;
3055         int                     ntups;
3056         int                     i;
3057         PQExpBuffer query;
3058         ExtensionInfo *extinfo;
3059         int                     i_tableoid;
3060         int                     i_oid;
3061         int                     i_extname;
3062         int                     i_nspname;
3063         int                     i_extrelocatable;
3064         int                     i_extversion;
3065         int                     i_extconfig;
3066         int                     i_extcondition;
3067
3068         /*
3069          * Before 9.1, there are no extensions.
3070          */
3071         if (fout->remoteVersion < 90100)
3072         {
3073                 *numExtensions = 0;
3074                 return NULL;
3075         }
3076
3077         query = createPQExpBuffer();
3078
3079         /* Make sure we are in proper schema */
3080         selectSourceSchema(fout, "pg_catalog");
3081
3082         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
3083                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3084                                           "FROM pg_extension x "
3085                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
3086
3087         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3088
3089         ntups = PQntuples(res);
3090
3091         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3092
3093         i_tableoid = PQfnumber(res, "tableoid");
3094         i_oid = PQfnumber(res, "oid");
3095         i_extname = PQfnumber(res, "extname");
3096         i_nspname = PQfnumber(res, "nspname");
3097         i_extrelocatable = PQfnumber(res, "extrelocatable");
3098         i_extversion = PQfnumber(res, "extversion");
3099         i_extconfig = PQfnumber(res, "extconfig");
3100         i_extcondition = PQfnumber(res, "extcondition");
3101
3102         for (i = 0; i < ntups; i++)
3103         {
3104                 extinfo[i].dobj.objType = DO_EXTENSION;
3105                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3106                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3107                 AssignDumpId(&extinfo[i].dobj);
3108                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3109                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3110                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3111                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3112                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3113                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3114
3115                 /* Decide whether we want to dump it */
3116                 selectDumpableExtension(&(extinfo[i]));
3117         }
3118
3119         PQclear(res);
3120         destroyPQExpBuffer(query);
3121
3122         *numExtensions = ntups;
3123
3124         return extinfo;
3125 }
3126
3127 /*
3128  * getTypes:
3129  *        read all types in the system catalogs and return them in the
3130  * TypeInfo* structure
3131  *
3132  *      numTypes is set to the number of types read in
3133  *
3134  * NB: this must run after getFuncs() because we assume we can do
3135  * findFuncByOid().
3136  */
3137 TypeInfo *
3138 getTypes(Archive *fout, int *numTypes)
3139 {
3140         PGresult   *res;
3141         int                     ntups;
3142         int                     i;
3143         PQExpBuffer query = createPQExpBuffer();
3144         TypeInfo   *tyinfo;
3145         ShellTypeInfo *stinfo;
3146         int                     i_tableoid;
3147         int                     i_oid;
3148         int                     i_typname;
3149         int                     i_typnamespace;
3150         int                     i_typacl;
3151         int                     i_rolname;
3152         int                     i_typinput;
3153         int                     i_typoutput;
3154         int                     i_typelem;
3155         int                     i_typrelid;
3156         int                     i_typrelkind;
3157         int                     i_typtype;
3158         int                     i_typisdefined;
3159         int                     i_isarray;
3160
3161         /*
3162          * we include even the built-in types because those may be used as array
3163          * elements by user-defined types
3164          *
3165          * we filter out the built-in types when we dump out the types
3166          *
3167          * same approach for undefined (shell) types and array types
3168          *
3169          * Note: as of 8.3 we can reliably detect whether a type is an
3170          * auto-generated array type by checking the element type's typarray.
3171          * (Before that the test is capable of generating false positives.) We
3172          * still check for name beginning with '_', though, so as to avoid the
3173          * cost of the subselect probe for all standard types.  This would have to
3174          * be revisited if the backend ever allows renaming of array types.
3175          */
3176
3177         /* Make sure we are in proper schema */
3178         selectSourceSchema(fout, "pg_catalog");
3179
3180         if (fout->remoteVersion >= 90200)
3181         {
3182                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3183                                                   "typnamespace, typacl, "
3184                                                   "(%s typowner) AS rolname, "
3185                                                   "typinput::oid AS typinput, "
3186                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3187                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3188                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3189                                                   "typtype, typisdefined, "
3190                                                   "typname[0] = '_' AND typelem != 0 AND "
3191                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3192                                                   "FROM pg_type",
3193                                                   username_subquery);
3194         }
3195         else if (fout->remoteVersion >= 80300)
3196         {
3197                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3198                                                   "typnamespace, '{=U}' AS typacl, "
3199                                                   "(%s typowner) AS rolname, "
3200                                                   "typinput::oid AS typinput, "
3201                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3202                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3203                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3204                                                   "typtype, typisdefined, "
3205                                                   "typname[0] = '_' AND typelem != 0 AND "
3206                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3207                                                   "FROM pg_type",
3208                                                   username_subquery);
3209         }
3210         else if (fout->remoteVersion >= 70300)
3211         {
3212                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3213                                                   "typnamespace, '{=U}' AS typacl, "
3214                                                   "(%s typowner) AS rolname, "
3215                                                   "typinput::oid AS typinput, "
3216                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3217                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3218                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3219                                                   "typtype, typisdefined, "
3220                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3221                                                   "FROM pg_type",
3222                                                   username_subquery);
3223         }
3224         else if (fout->remoteVersion >= 70100)
3225         {
3226                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3227                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3228                                                   "(%s typowner) AS rolname, "
3229                                                   "typinput::oid AS typinput, "
3230                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3231                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3232                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3233                                                   "typtype, typisdefined, "
3234                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3235                                                   "FROM pg_type",
3236                                                   username_subquery);
3237         }
3238         else
3239         {
3240                 appendPQExpBuffer(query, "SELECT "
3241                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3242                                                   "oid, typname, "
3243                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3244                                                   "(%s typowner) AS rolname, "
3245                                                   "typinput::oid AS typinput, "
3246                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3247                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3248                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3249                                                   "typtype, typisdefined, "
3250                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3251                                                   "FROM pg_type",
3252                                                   username_subquery);
3253         }
3254
3255         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3256
3257         ntups = PQntuples(res);
3258
3259         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3260
3261         i_tableoid = PQfnumber(res, "tableoid");
3262         i_oid = PQfnumber(res, "oid");
3263         i_typname = PQfnumber(res, "typname");
3264         i_typnamespace = PQfnumber(res, "typnamespace");
3265         i_typacl = PQfnumber(res, "typacl");
3266         i_rolname = PQfnumber(res, "rolname");
3267         i_typinput = PQfnumber(res, "typinput");
3268         i_typoutput = PQfnumber(res, "typoutput");
3269         i_typelem = PQfnumber(res, "typelem");
3270         i_typrelid = PQfnumber(res, "typrelid");
3271         i_typrelkind = PQfnumber(res, "typrelkind");
3272         i_typtype = PQfnumber(res, "typtype");
3273         i_typisdefined = PQfnumber(res, "typisdefined");
3274         i_isarray = PQfnumber(res, "isarray");
3275
3276         for (i = 0; i < ntups; i++)
3277         {
3278                 tyinfo[i].dobj.objType = DO_TYPE;
3279                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3280                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3281                 AssignDumpId(&tyinfo[i].dobj);
3282                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3283                 tyinfo[i].dobj.namespace =
3284                         findNamespace(fout,
3285                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3286                                                   tyinfo[i].dobj.catId.oid);
3287                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3288                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3289                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3290                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3291                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3292                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3293                 tyinfo[i].shellType = NULL;
3294
3295                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3296                         tyinfo[i].isDefined = true;
3297                 else
3298                         tyinfo[i].isDefined = false;
3299
3300                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3301                         tyinfo[i].isArray = true;
3302                 else
3303                         tyinfo[i].isArray = false;
3304
3305                 /* Decide whether we want to dump it */
3306                 selectDumpableType(&tyinfo[i]);
3307
3308                 /*
3309                  * If it's a domain, fetch info about its constraints, if any
3310                  */
3311                 tyinfo[i].nDomChecks = 0;
3312                 tyinfo[i].domChecks = NULL;
3313                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3314                         getDomainConstraints(fout, &(tyinfo[i]));
3315
3316                 /*
3317                  * If it's a base type, make a DumpableObject representing a shell
3318                  * definition of the type.      We will need to dump that ahead of the I/O
3319                  * functions for the type.      Similarly, range types need a shell
3320                  * definition in case they have a canonicalize function.
3321                  *
3322                  * Note: the shell type doesn't have a catId.  You might think it
3323                  * should copy the base type's catId, but then it might capture the
3324                  * pg_depend entries for the type, which we don't want.
3325                  */
3326                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3327                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3328                 {
3329                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3330                         stinfo->dobj.objType = DO_SHELL_TYPE;
3331                         stinfo->dobj.catId = nilCatalogId;
3332                         AssignDumpId(&stinfo->dobj);
3333                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3334                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3335                         stinfo->baseType = &(tyinfo[i]);
3336                         tyinfo[i].shellType = stinfo;
3337
3338                         /*
3339                          * Initially mark the shell type as not to be dumped.  We'll only
3340                          * dump it if the I/O or canonicalize functions need to be dumped;
3341                          * this is taken care of while sorting dependencies.
3342                          */
3343                         stinfo->dobj.dump = false;
3344
3345                         /*
3346                          * However, if dumping from pre-7.3, there will be no dependency
3347                          * info so we have to fake it here.  We only need to worry about
3348                          * typinput and typoutput since the other functions only exist
3349                          * post-7.3.
3350                          */
3351                         if (fout->remoteVersion < 70300)
3352                         {
3353                                 Oid                     typinput;
3354                                 Oid                     typoutput;
3355                                 FuncInfo   *funcInfo;
3356
3357                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3358                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3359
3360                                 funcInfo = findFuncByOid(typinput);
3361                                 if (funcInfo && funcInfo->dobj.dump)
3362                                 {
3363                                         /* base type depends on function */
3364                                         addObjectDependency(&tyinfo[i].dobj,
3365                                                                                 funcInfo->dobj.dumpId);
3366                                         /* function depends on shell type */
3367                                         addObjectDependency(&funcInfo->dobj,
3368                                                                                 stinfo->dobj.dumpId);
3369                                         /* mark shell type as to be dumped */
3370                                         stinfo->dobj.dump = true;
3371                                 }
3372
3373                                 funcInfo = findFuncByOid(typoutput);
3374                                 if (funcInfo && funcInfo->dobj.dump)
3375                                 {
3376                                         /* base type depends on function */
3377                                         addObjectDependency(&tyinfo[i].dobj,
3378                                                                                 funcInfo->dobj.dumpId);
3379                                         /* function depends on shell type */
3380                                         addObjectDependency(&funcInfo->dobj,
3381                                                                                 stinfo->dobj.dumpId);
3382                                         /* mark shell type as to be dumped */
3383                                         stinfo->dobj.dump = true;
3384                                 }
3385                         }
3386                 }
3387
3388                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3389                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3390                                           tyinfo[i].dobj.name);
3391         }
3392
3393         *numTypes = ntups;
3394
3395         PQclear(res);
3396
3397         destroyPQExpBuffer(query);
3398
3399         return tyinfo;
3400 }
3401
3402 /*
3403  * getOperators:
3404  *        read all operators in the system catalogs and return them in the
3405  * OprInfo* structure
3406  *
3407  *      numOprs is set to the number of operators read in
3408  */
3409 OprInfo *
3410 getOperators(Archive *fout, int *numOprs)
3411 {
3412         PGresult   *res;
3413         int                     ntups;
3414         int                     i;
3415         PQExpBuffer query = createPQExpBuffer();
3416         OprInfo    *oprinfo;
3417         int                     i_tableoid;
3418         int                     i_oid;
3419         int                     i_oprname;
3420         int                     i_oprnamespace;
3421         int                     i_rolname;
3422         int                     i_oprkind;
3423         int                     i_oprcode;
3424
3425         /*
3426          * find all operators, including builtin operators; we filter out
3427          * system-defined operators at dump-out time.
3428          */
3429
3430         /* Make sure we are in proper schema */
3431         selectSourceSchema(fout, "pg_catalog");
3432
3433         if (fout->remoteVersion >= 70300)
3434         {
3435                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3436                                                   "oprnamespace, "
3437                                                   "(%s oprowner) AS rolname, "
3438                                                   "oprkind, "
3439                                                   "oprcode::oid AS oprcode "
3440                                                   "FROM pg_operator",
3441                                                   username_subquery);
3442         }
3443         else if (fout->remoteVersion >= 70100)
3444         {
3445                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3446                                                   "0::oid AS oprnamespace, "
3447                                                   "(%s oprowner) AS rolname, "
3448                                                   "oprkind, "
3449                                                   "oprcode::oid AS oprcode "
3450                                                   "FROM pg_operator",
3451                                                   username_subquery);
3452         }
3453         else
3454         {
3455                 appendPQExpBuffer(query, "SELECT "
3456                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3457                                                   "oid, oprname, "
3458                                                   "0::oid AS oprnamespace, "
3459                                                   "(%s oprowner) AS rolname, "
3460                                                   "oprkind, "
3461                                                   "oprcode::oid AS oprcode "
3462                                                   "FROM pg_operator",
3463                                                   username_subquery);
3464         }
3465
3466         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3467
3468         ntups = PQntuples(res);
3469         *numOprs = ntups;
3470
3471         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3472
3473         i_tableoid = PQfnumber(res, "tableoid");
3474         i_oid = PQfnumber(res, "oid");
3475         i_oprname = PQfnumber(res, "oprname");
3476         i_oprnamespace = PQfnumber(res, "oprnamespace");
3477         i_rolname = PQfnumber(res, "rolname");
3478         i_oprkind = PQfnumber(res, "oprkind");
3479         i_oprcode = PQfnumber(res, "oprcode");
3480
3481         for (i = 0; i < ntups; i++)
3482         {
3483                 oprinfo[i].dobj.objType = DO_OPERATOR;
3484                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3485                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3486                 AssignDumpId(&oprinfo[i].dobj);
3487                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3488                 oprinfo[i].dobj.namespace =
3489                         findNamespace(fout,
3490                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3491                                                   oprinfo[i].dobj.catId.oid);
3492                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3493                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3494                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3495
3496                 /* Decide whether we want to dump it */
3497                 selectDumpableObject(&(oprinfo[i].dobj));
3498
3499                 if (strlen(oprinfo[i].rolname) == 0)
3500                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3501                                           oprinfo[i].dobj.name);
3502         }
3503
3504         PQclear(res);
3505
3506         destroyPQExpBuffer(query);
3507
3508         return oprinfo;
3509 }
3510
3511 /*
3512  * getCollations:
3513  *        read all collations in the system catalogs and return them in the
3514  * CollInfo* structure
3515  *
3516  *      numCollations is set to the number of collations read in
3517  */
3518 CollInfo *
3519 getCollations(Archive *fout, int *numCollations)
3520 {
3521         PGresult   *res;
3522         int                     ntups;
3523         int                     i;
3524         PQExpBuffer query;
3525         CollInfo   *collinfo;
3526         int                     i_tableoid;
3527         int                     i_oid;
3528         int                     i_collname;
3529         int                     i_collnamespace;
3530         int                     i_rolname;
3531
3532         /* Collations didn't exist pre-9.1 */
3533         if (fout->remoteVersion < 90100)
3534         {
3535                 *numCollations = 0;
3536                 return NULL;
3537         }
3538
3539         query = createPQExpBuffer();
3540
3541         /*
3542          * find all collations, including builtin collations; we filter out
3543          * system-defined collations at dump-out time.
3544          */
3545
3546         /* Make sure we are in proper schema */
3547         selectSourceSchema(fout, "pg_catalog");
3548
3549         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3550                                           "collnamespace, "
3551                                           "(%s collowner) AS rolname "
3552                                           "FROM pg_collation",
3553                                           username_subquery);
3554
3555         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3556
3557         ntups = PQntuples(res);
3558         *numCollations = ntups;
3559
3560         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3561
3562         i_tableoid = PQfnumber(res, "tableoid");
3563         i_oid = PQfnumber(res, "oid");
3564         i_collname = PQfnumber(res, "collname");
3565         i_collnamespace = PQfnumber(res, "collnamespace");
3566         i_rolname = PQfnumber(res, "rolname");
3567
3568         for (i = 0; i < ntups; i++)
3569         {
3570                 collinfo[i].dobj.objType = DO_COLLATION;
3571                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3572                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3573                 AssignDumpId(&collinfo[i].dobj);
3574                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3575                 collinfo[i].dobj.namespace =
3576                         findNamespace(fout,
3577                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3578                                                   collinfo[i].dobj.catId.oid);
3579                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3580
3581                 /* Decide whether we want to dump it */
3582                 selectDumpableObject(&(collinfo[i].dobj));
3583         }
3584
3585         PQclear(res);
3586
3587         destroyPQExpBuffer(query);
3588
3589         return collinfo;
3590 }
3591
3592 /*
3593  * getConversions:
3594  *        read all conversions in the system catalogs and return them in the
3595  * ConvInfo* structure
3596  *
3597  *      numConversions is set to the number of conversions read in
3598  */
3599 ConvInfo *
3600 getConversions(Archive *fout, int *numConversions)
3601 {
3602         PGresult   *res;
3603         int                     ntups;
3604         int                     i;
3605         PQExpBuffer query = createPQExpBuffer();
3606         ConvInfo   *convinfo;
3607         int                     i_tableoid;
3608         int                     i_oid;
3609         int                     i_conname;
3610         int                     i_connamespace;
3611         int                     i_rolname;
3612
3613         /* Conversions didn't exist pre-7.3 */
3614         if (fout->remoteVersion < 70300)
3615         {
3616                 *numConversions = 0;
3617                 return NULL;
3618         }
3619
3620         /*
3621          * find all conversions, including builtin conversions; we filter out
3622          * system-defined conversions at dump-out time.
3623          */
3624
3625         /* Make sure we are in proper schema */
3626         selectSourceSchema(fout, "pg_catalog");
3627
3628         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3629                                           "connamespace, "
3630                                           "(%s conowner) AS rolname "
3631                                           "FROM pg_conversion",
3632                                           username_subquery);
3633
3634         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3635
3636         ntups = PQntuples(res);
3637         *numConversions = ntups;
3638
3639         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3640
3641         i_tableoid = PQfnumber(res, "tableoid");
3642         i_oid = PQfnumber(res, "oid");
3643         i_conname = PQfnumber(res, "conname");
3644         i_connamespace = PQfnumber(res, "connamespace");
3645         i_rolname = PQfnumber(res, "rolname");
3646
3647         for (i = 0; i < ntups; i++)
3648         {
3649                 convinfo[i].dobj.objType = DO_CONVERSION;
3650                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3651                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3652                 AssignDumpId(&convinfo[i].dobj);
3653                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3654                 convinfo[i].dobj.namespace =
3655                         findNamespace(fout,
3656                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3657                                                   convinfo[i].dobj.catId.oid);
3658                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3659
3660                 /* Decide whether we want to dump it */
3661                 selectDumpableObject(&(convinfo[i].dobj));
3662         }
3663
3664         PQclear(res);
3665
3666         destroyPQExpBuffer(query);
3667
3668         return convinfo;
3669 }
3670
3671 /*
3672  * getOpclasses:
3673  *        read all opclasses in the system catalogs and return them in the
3674  * OpclassInfo* structure
3675  *
3676  *      numOpclasses is set to the number of opclasses read in
3677  */
3678 OpclassInfo *
3679 getOpclasses(Archive *fout, int *numOpclasses)
3680 {
3681         PGresult   *res;
3682         int                     ntups;
3683         int                     i;
3684         PQExpBuffer query = createPQExpBuffer();
3685         OpclassInfo *opcinfo;
3686         int                     i_tableoid;
3687         int                     i_oid;
3688         int                     i_opcname;
3689         int                     i_opcnamespace;
3690         int                     i_rolname;
3691
3692         /*
3693          * find all opclasses, including builtin opclasses; we filter out
3694          * system-defined opclasses at dump-out time.
3695          */
3696
3697         /* Make sure we are in proper schema */
3698         selectSourceSchema(fout, "pg_catalog");
3699
3700         if (fout->remoteVersion >= 70300)
3701         {
3702                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3703                                                   "opcnamespace, "
3704                                                   "(%s opcowner) AS rolname "
3705                                                   "FROM pg_opclass",
3706                                                   username_subquery);
3707         }
3708         else if (fout->remoteVersion >= 70100)
3709         {
3710                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3711                                                   "0::oid AS opcnamespace, "
3712                                                   "''::name AS rolname "
3713                                                   "FROM pg_opclass");
3714         }
3715         else
3716         {
3717                 appendPQExpBuffer(query, "SELECT "
3718                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3719                                                   "oid, opcname, "
3720                                                   "0::oid AS opcnamespace, "
3721                                                   "''::name AS rolname "
3722                                                   "FROM pg_opclass");
3723         }
3724
3725         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3726
3727         ntups = PQntuples(res);
3728         *numOpclasses = ntups;
3729
3730         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3731
3732         i_tableoid = PQfnumber(res, "tableoid");
3733         i_oid = PQfnumber(res, "oid");
3734         i_opcname = PQfnumber(res, "opcname");
3735         i_opcnamespace = PQfnumber(res, "opcnamespace");
3736         i_rolname = PQfnumber(res, "rolname");
3737
3738         for (i = 0; i < ntups; i++)
3739         {
3740                 opcinfo[i].dobj.objType = DO_OPCLASS;
3741                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3742                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3743                 AssignDumpId(&opcinfo[i].dobj);
3744                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3745                 opcinfo[i].dobj.namespace =
3746                         findNamespace(fout,
3747                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3748                                                   opcinfo[i].dobj.catId.oid);
3749                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3750
3751                 /* Decide whether we want to dump it */
3752                 selectDumpableObject(&(opcinfo[i].dobj));
3753
3754                 if (fout->remoteVersion >= 70300)
3755                 {
3756                         if (strlen(opcinfo[i].rolname) == 0)
3757                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3758                                                   opcinfo[i].dobj.name);
3759                 }
3760         }
3761
3762         PQclear(res);
3763
3764         destroyPQExpBuffer(query);
3765
3766         return opcinfo;
3767 }
3768
3769 /*
3770  * getOpfamilies:
3771  *        read all opfamilies in the system catalogs and return them in the
3772  * OpfamilyInfo* structure
3773  *
3774  *      numOpfamilies is set to the number of opfamilies read in
3775  */
3776 OpfamilyInfo *
3777 getOpfamilies(Archive *fout, int *numOpfamilies)
3778 {
3779         PGresult   *res;
3780         int                     ntups;
3781         int                     i;
3782         PQExpBuffer query;
3783         OpfamilyInfo *opfinfo;
3784         int                     i_tableoid;
3785         int                     i_oid;
3786         int                     i_opfname;
3787         int                     i_opfnamespace;
3788         int                     i_rolname;
3789
3790         /* Before 8.3, there is no separate concept of opfamilies */
3791         if (fout->remoteVersion < 80300)
3792         {
3793                 *numOpfamilies = 0;
3794                 return NULL;
3795         }
3796
3797         query = createPQExpBuffer();
3798
3799         /*
3800          * find all opfamilies, including builtin opfamilies; we filter out
3801          * system-defined opfamilies at dump-out time.
3802          */
3803
3804         /* Make sure we are in proper schema */
3805         selectSourceSchema(fout, "pg_catalog");
3806
3807         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3808                                           "opfnamespace, "
3809                                           "(%s opfowner) AS rolname "
3810                                           "FROM pg_opfamily",
3811                                           username_subquery);
3812
3813         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3814
3815         ntups = PQntuples(res);
3816         *numOpfamilies = ntups;
3817
3818         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3819
3820         i_tableoid = PQfnumber(res, "tableoid");
3821         i_oid = PQfnumber(res, "oid");
3822         i_opfname = PQfnumber(res, "opfname");
3823         i_opfnamespace = PQfnumber(res, "opfnamespace");
3824         i_rolname = PQfnumber(res, "rolname");
3825
3826         for (i = 0; i < ntups; i++)
3827         {
3828                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3829                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3830                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3831                 AssignDumpId(&opfinfo[i].dobj);
3832                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3833                 opfinfo[i].dobj.namespace =
3834                         findNamespace(fout,
3835                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3836                                                   opfinfo[i].dobj.catId.oid);
3837                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3838
3839                 /* Decide whether we want to dump it */
3840                 selectDumpableObject(&(opfinfo[i].dobj));
3841
3842                 if (fout->remoteVersion >= 70300)
3843                 {
3844                         if (strlen(opfinfo[i].rolname) == 0)
3845                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3846                                                   opfinfo[i].dobj.name);
3847                 }
3848         }
3849
3850         PQclear(res);
3851
3852         destroyPQExpBuffer(query);
3853
3854         return opfinfo;
3855 }
3856
3857 /*
3858  * getAggregates:
3859  *        read all the user-defined aggregates in the system catalogs and
3860  * return them in the AggInfo* structure
3861  *
3862  * numAggs is set to the number of aggregates read in
3863  */
3864 AggInfo *
3865 getAggregates(Archive *fout, int *numAggs)
3866 {
3867         PGresult   *res;
3868         int                     ntups;
3869         int                     i;
3870         PQExpBuffer query = createPQExpBuffer();
3871         AggInfo    *agginfo;
3872         int                     i_tableoid;
3873         int                     i_oid;
3874         int                     i_aggname;
3875         int                     i_aggnamespace;
3876         int                     i_pronargs;
3877         int                     i_proargtypes;
3878         int                     i_rolname;
3879         int                     i_aggacl;
3880         int                     i_proiargs;
3881
3882         /* Make sure we are in proper schema */
3883         selectSourceSchema(fout, "pg_catalog");
3884
3885         /*
3886          * Find all user-defined aggregates.  See comment in getFuncs() for the
3887          * rationale behind the filtering logic.
3888          */
3889
3890         if (fout->remoteVersion >= 80400)
3891         {
3892                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3893                                                   "pronamespace AS aggnamespace, "
3894                                                   "pronargs, proargtypes, "
3895                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
3896                                                   "(%s proowner) AS rolname, "
3897                                                   "proacl AS aggacl "
3898                                                   "FROM pg_proc p "
3899                                                   "WHERE proisagg AND ("
3900                                                   "pronamespace != "
3901                                                   "(SELECT oid FROM pg_namespace "
3902                                                   "WHERE nspname = 'pg_catalog')",
3903                                                   username_subquery);
3904                 if (binary_upgrade && fout->remoteVersion >= 90100)
3905                         appendPQExpBuffer(query,
3906                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3907                                                           "classid = 'pg_proc'::regclass AND "
3908                                                           "objid = p.oid AND "
3909                                                           "refclassid = 'pg_extension'::regclass AND "
3910                                                           "deptype = 'e')");
3911                 appendPQExpBuffer(query, ")");
3912         }
3913         else if (fout->remoteVersion >= 80200)
3914         {
3915                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3916                                                   "pronamespace AS aggnamespace, "
3917                                                   "pronargs, proargtypes, "
3918                                                   "NULL::text AS proiargs,"
3919                                                   "(%s proowner) AS rolname, "
3920                                                   "proacl AS aggacl "
3921                                                   "FROM pg_proc p "
3922                                                   "WHERE proisagg AND ("
3923                                                   "pronamespace != "
3924                                                   "(SELECT oid FROM pg_namespace "
3925                                                   "WHERE nspname = 'pg_catalog'))",
3926                                                   username_subquery);
3927         }
3928         else if (fout->remoteVersion >= 70300)
3929         {
3930                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3931                                                   "pronamespace AS aggnamespace, "
3932                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3933                                                   "proargtypes, "
3934                                                   "NULL::text AS proiargs, "
3935                                                   "(%s proowner) AS rolname, "
3936                                                   "proacl AS aggacl "
3937                                                   "FROM pg_proc "
3938                                                   "WHERE proisagg "
3939                                                   "AND pronamespace != "
3940                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3941                                                   username_subquery);
3942         }
3943         else if (fout->remoteVersion >= 70100)
3944         {
3945                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3946                                                   "0::oid AS aggnamespace, "
3947                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3948                                                   "aggbasetype AS proargtypes, "
3949                                                   "NULL::text AS proiargs, "
3950                                                   "(%s aggowner) AS rolname, "
3951                                                   "'{=X}' AS aggacl "
3952                                                   "FROM pg_aggregate "
3953                                                   "where oid > '%u'::oid",
3954                                                   username_subquery,
3955                                                   g_last_builtin_oid);
3956         }
3957         else
3958         {
3959                 appendPQExpBuffer(query, "SELECT "
3960                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3961                                                   "oid, aggname, "
3962                                                   "0::oid AS aggnamespace, "
3963                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3964                                                   "aggbasetype AS proargtypes, "
3965                                                   "NULL::text AS proiargs, "
3966                                                   "(%s aggowner) AS rolname, "
3967                                                   "'{=X}' AS aggacl "
3968                                                   "FROM pg_aggregate "
3969                                                   "where oid > '%u'::oid",
3970                                                   username_subquery,
3971                                                   g_last_builtin_oid);
3972         }
3973
3974         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3975
3976         ntups = PQntuples(res);
3977         *numAggs = ntups;
3978
3979         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3980
3981         i_tableoid = PQfnumber(res, "tableoid");
3982         i_oid = PQfnumber(res, "oid");
3983         i_aggname = PQfnumber(res, "aggname");
3984         i_aggnamespace = PQfnumber(res, "aggnamespace");
3985         i_pronargs = PQfnumber(res, "pronargs");
3986         i_proargtypes = PQfnumber(res, "proargtypes");
3987         i_rolname = PQfnumber(res, "rolname");
3988         i_aggacl = PQfnumber(res, "aggacl");
3989         i_proiargs = PQfnumber(res, "proiargs");
3990
3991         for (i = 0; i < ntups; i++)
3992         {
3993                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3994                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3995                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3996                 AssignDumpId(&agginfo[i].aggfn.dobj);
3997                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3998                 agginfo[i].aggfn.dobj.namespace =
3999                         findNamespace(fout,
4000                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
4001                                                   agginfo[i].aggfn.dobj.catId.oid);
4002                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4003                 if (strlen(agginfo[i].aggfn.rolname) == 0)
4004                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
4005                                           agginfo[i].aggfn.dobj.name);
4006                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
4007                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
4008                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
4009                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4010                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
4011                 if (agginfo[i].aggfn.nargs == 0)
4012                         agginfo[i].aggfn.argtypes = NULL;
4013                 else
4014                 {
4015                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
4016                         if (fout->remoteVersion >= 70300)
4017                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
4018                                                           agginfo[i].aggfn.argtypes,
4019                                                           agginfo[i].aggfn.nargs);
4020                         else
4021                                 /* it's just aggbasetype */
4022                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
4023                 }
4024
4025                 /* Decide whether we want to dump it */
4026                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
4027         }
4028
4029         PQclear(res);
4030
4031         destroyPQExpBuffer(query);
4032
4033         return agginfo;
4034 }
4035
4036 /*
4037  * getFuncs:
4038  *        read all the user-defined functions in the system catalogs and
4039  * return them in the FuncInfo* structure
4040  *
4041  * numFuncs is set to the number of functions read in
4042  */
4043 FuncInfo *
4044 getFuncs(Archive *fout, int *numFuncs)
4045 {
4046         PGresult   *res;
4047         int                     ntups;
4048         int                     i;
4049         PQExpBuffer query = createPQExpBuffer();
4050         FuncInfo   *finfo;
4051         int                     i_tableoid;
4052         int                     i_oid;
4053         int                     i_proname;
4054         int                     i_pronamespace;
4055         int                     i_rolname;
4056         int                     i_prolang;
4057         int                     i_pronargs;
4058         int                     i_proargtypes;
4059         int                     i_prorettype;
4060         int                     i_proacl;
4061         int                     i_proiargs;
4062
4063         /* Make sure we are in proper schema */
4064         selectSourceSchema(fout, "pg_catalog");
4065
4066         /*
4067          * Find all user-defined functions.  Normally we can exclude functions in
4068          * pg_catalog, which is worth doing since there are several thousand of
4069          * 'em.  However, there are some extensions that create functions in
4070          * pg_catalog.  In normal dumps we can still ignore those --- but in
4071          * binary-upgrade mode, we must dump the member objects of the extension,
4072          * so be sure to fetch any such functions.
4073          *
4074          * Also, in 9.2 and up, exclude functions that are internally dependent on
4075          * something else, since presumably those will be created as a result of
4076          * creating the something else.  This currently only acts to suppress
4077          * constructor functions for range types.  Note that this is OK only
4078          * because the constructors don't have any dependencies the range type
4079          * doesn't have; otherwise we might not get creation ordering correct.
4080          */
4081
4082         if (fout->remoteVersion >= 80400)
4083         {
4084                 appendPQExpBuffer(query,
4085                                                   "SELECT tableoid, oid, proname, prolang, "
4086                                                   "pronargs, proargtypes, prorettype, proacl, "
4087                                                   "pronamespace, "
4088                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4089                                                   "(%s proowner) AS rolname "
4090                                                   "FROM pg_proc p "
4091                                                   "WHERE NOT proisagg AND ("
4092                                                   "pronamespace != "
4093                                                   "(SELECT oid FROM pg_namespace "
4094                                                   "WHERE nspname = 'pg_catalog')",
4095                                                   username_subquery);
4096                 if (fout->remoteVersion >= 90200)
4097                         appendPQExpBuffer(query,
4098                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4099                                                           "WHERE classid = 'pg_proc'::regclass AND "
4100                                                           "objid = p.oid AND deptype = 'i')");
4101                 if (binary_upgrade && fout->remoteVersion >= 90100)
4102                         appendPQExpBuffer(query,
4103                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4104                                                           "classid = 'pg_proc'::regclass AND "
4105                                                           "objid = p.oid AND "
4106                                                           "refclassid = 'pg_extension'::regclass AND "
4107                                                           "deptype = 'e')");
4108                 appendPQExpBuffer(query, ")");
4109         }
4110         else if (fout->remoteVersion >= 70300)
4111         {
4112                 appendPQExpBuffer(query,
4113                                                   "SELECT tableoid, oid, proname, prolang, "
4114                                                   "pronargs, proargtypes, prorettype, proacl, "
4115                                                   "pronamespace, "
4116                                                   "NULL::text AS proiargs,"
4117                                                   "(%s proowner) AS rolname "
4118                                                   "FROM pg_proc p "
4119                                                   "WHERE NOT proisagg AND ("
4120                                                   "pronamespace != "
4121                                                   "(SELECT oid FROM pg_namespace "
4122                                                   "WHERE nspname = 'pg_catalog'))",
4123                                                   username_subquery);
4124         }
4125         else if (fout->remoteVersion >= 70100)
4126         {
4127                 appendPQExpBuffer(query,
4128                                                   "SELECT tableoid, oid, proname, prolang, "
4129                                                   "pronargs, proargtypes, prorettype, "
4130                                                   "'{=X}' AS proacl, "
4131                                                   "0::oid AS pronamespace, "
4132                                                   "NULL::text AS proiargs,"
4133                                                   "(%s proowner) AS rolname "
4134                                                   "FROM pg_proc "
4135                                                   "WHERE pg_proc.oid > '%u'::oid",
4136                                                   username_subquery,
4137                                                   g_last_builtin_oid);
4138         }
4139         else
4140         {
4141                 appendPQExpBuffer(query,
4142                                                   "SELECT "
4143                                                   "(SELECT oid FROM pg_class "
4144                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4145                                                   "oid, proname, prolang, "
4146                                                   "pronargs, proargtypes, prorettype, "
4147                                                   "'{=X}' AS proacl, "
4148                                                   "0::oid AS pronamespace, "
4149                                                   "NULL::text AS proiargs,"
4150                                                   "(%s proowner) AS rolname "
4151                                                   "FROM pg_proc "
4152                                                   "where pg_proc.oid > '%u'::oid",
4153                                                   username_subquery,
4154                                                   g_last_builtin_oid);
4155         }
4156
4157         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4158
4159         ntups = PQntuples(res);
4160
4161         *numFuncs = ntups;
4162
4163         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4164
4165         i_tableoid = PQfnumber(res, "tableoid");
4166         i_oid = PQfnumber(res, "oid");
4167         i_proname = PQfnumber(res, "proname");
4168         i_pronamespace = PQfnumber(res, "pronamespace");
4169         i_rolname = PQfnumber(res, "rolname");
4170         i_prolang = PQfnumber(res, "prolang");
4171         i_pronargs = PQfnumber(res, "pronargs");
4172         i_proargtypes = PQfnumber(res, "proargtypes");
4173         i_prorettype = PQfnumber(res, "prorettype");
4174         i_proacl = PQfnumber(res, "proacl");
4175         i_proiargs = PQfnumber(res, "proiargs");
4176
4177         for (i = 0; i < ntups; i++)
4178         {
4179                 finfo[i].dobj.objType = DO_FUNC;
4180                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4181                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4182                 AssignDumpId(&finfo[i].dobj);
4183                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4184                 finfo[i].dobj.namespace =
4185                         findNamespace(fout,
4186                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4187                                                   finfo[i].dobj.catId.oid);
4188                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4189                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4190                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4191                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4192                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4193                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4194                 if (finfo[i].nargs == 0)
4195                         finfo[i].argtypes = NULL;
4196                 else
4197                 {
4198                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4199                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4200                                                   finfo[i].argtypes, finfo[i].nargs);
4201                 }
4202
4203                 /* Decide whether we want to dump it */
4204                 selectDumpableObject(&(finfo[i].dobj));
4205
4206                 if (strlen(finfo[i].rolname) == 0)
4207                         write_msg(NULL,
4208                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4209                                           finfo[i].dobj.name);
4210         }
4211
4212         PQclear(res);
4213
4214         destroyPQExpBuffer(query);
4215
4216         return finfo;
4217 }
4218
4219 /*
4220  * getTables
4221  *        read all the user-defined tables (no indexes, no catalogs)
4222  * in the system catalogs return them in the TableInfo* structure
4223  *
4224  * numTables is set to the number of tables read in
4225  */
4226 TableInfo *
4227 getTables(Archive *fout, int *numTables)
4228 {
4229         PGresult   *res;
4230         int                     ntups;
4231         int                     i;
4232         PQExpBuffer query = createPQExpBuffer();
4233         TableInfo  *tblinfo;
4234         int                     i_reltableoid;
4235         int                     i_reloid;
4236         int                     i_relname;
4237         int                     i_relnamespace;
4238         int                     i_relkind;
4239         int                     i_relacl;
4240         int                     i_rolname;
4241         int                     i_relchecks;
4242         int                     i_relhastriggers;
4243         int                     i_relhasindex;
4244         int                     i_relhasrules;
4245         int                     i_relhasoids;
4246         int                     i_relfrozenxid;
4247         int                     i_toastoid;
4248         int                     i_toastfrozenxid;
4249         int                     i_relpersistence;
4250         int                     i_relispopulated;
4251         int                     i_relreplident;
4252         int                     i_owning_tab;
4253         int                     i_owning_col;
4254         int                     i_reltablespace;
4255         int                     i_reloptions;
4256         int                     i_checkoption;
4257         int                     i_toastreloptions;
4258         int                     i_reloftype;
4259         int                     i_relpages;
4260
4261         /* Make sure we are in proper schema */
4262         selectSourceSchema(fout, "pg_catalog");
4263
4264         /*
4265          * Find all the tables and table-like objects.
4266          *
4267          * We include system catalogs, so that we can work if a user table is
4268          * defined to inherit from a system catalog (pretty weird, but...)
4269          *
4270          * We ignore relations that are not ordinary tables, sequences, views,
4271          * materialized views, composite types, or foreign tables.
4272          *
4273          * Composite-type table entries won't be dumped as such, but we have to
4274          * make a DumpableObject for them so that we can track dependencies of the
4275          * composite type (pg_depend entries for columns of the composite type
4276          * link to the pg_class entry not the pg_type entry).
4277          *
4278          * Note: in this phase we should collect only a minimal amount of
4279          * information about each table, basically just enough to decide if it is
4280          * interesting. We must fetch all tables in this phase because otherwise
4281          * we cannot correctly identify inherited columns, owned sequences, etc.
4282          */
4283
4284         if (fout->remoteVersion >= 90400)
4285         {
4286                 /*
4287                  * Left join to pick up dependency info linking sequences to their
4288                  * owning column, if any (note this dependency is AUTO as of 8.2)
4289                  */
4290                 appendPQExpBuffer(query,
4291                                                   "SELECT c.tableoid, c.oid, c.relname, "
4292                                                   "c.relacl, c.relkind, c.relnamespace, "
4293                                                   "(%s c.relowner) AS rolname, "
4294                                                   "c.relchecks, c.relhastriggers, "
4295                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4296                                                   "c.relfrozenxid, tc.oid AS toid, "
4297                                                   "tc.relfrozenxid AS tfrozenxid, "
4298                                                   "c.relpersistence, c.relispopulated, "
4299                                                   "c.relreplident, c.relpages, "
4300                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4301                                                   "d.refobjid AS owning_tab, "
4302                                                   "d.refobjsubid AS owning_col, "
4303                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4304                                                 "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4305                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4306                                                            "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4307                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4308                                                   "FROM pg_class c "
4309                                                   "LEFT JOIN pg_depend d ON "
4310                                                   "(c.relkind = '%c' AND "
4311                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4312                                                   "d.objsubid = 0 AND "
4313                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4314                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4315                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4316                                                   "ORDER BY c.oid",
4317                                                   username_subquery,
4318                                                   RELKIND_SEQUENCE,
4319                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4320                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4321                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4322         }
4323         else if (fout->remoteVersion >= 90300)
4324         {
4325                 /*
4326                  * Left join to pick up dependency info linking sequences to their
4327                  * owning column, if any (note this dependency is AUTO as of 8.2)
4328                  */
4329                 appendPQExpBuffer(query,
4330                                                   "SELECT c.tableoid, c.oid, c.relname, "
4331                                                   "c.relacl, c.relkind, c.relnamespace, "
4332                                                   "(%s c.relowner) AS rolname, "
4333                                                   "c.relchecks, c.relhastriggers, "
4334                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4335                                                   "c.relfrozenxid, tc.oid AS toid, "
4336                                                   "tc.relfrozenxid AS tfrozenxid, "
4337                                                   "c.relpersistence, c.relispopulated, "
4338                                                   "'d' AS relreplident, c.relpages, "
4339                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4340                                                   "d.refobjid AS owning_tab, "
4341                                                   "d.refobjsubid AS owning_col, "
4342                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4343                                                 "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4344                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4345                                                            "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4346                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4347                                                   "FROM pg_class c "
4348                                                   "LEFT JOIN pg_depend d ON "
4349                                                   "(c.relkind = '%c' AND "
4350                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4351                                                   "d.objsubid = 0 AND "
4352                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4353                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4354                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4355                                                   "ORDER BY c.oid",
4356                                                   username_subquery,
4357                                                   RELKIND_SEQUENCE,
4358                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4359                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4360                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4361         }
4362         else if (fout->remoteVersion >= 90100)
4363         {
4364                 /*
4365                  * Left join to pick up dependency info linking sequences to their
4366                  * owning column, if any (note this dependency is AUTO as of 8.2)
4367                  */
4368                 appendPQExpBuffer(query,
4369                                                   "SELECT c.tableoid, c.oid, c.relname, "
4370                                                   "c.relacl, c.relkind, c.relnamespace, "
4371                                                   "(%s c.relowner) AS rolname, "
4372                                                   "c.relchecks, c.relhastriggers, "
4373                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4374                                                   "c.relfrozenxid, tc.oid AS toid, "
4375                                                   "tc.relfrozenxid AS tfrozenxid, "
4376                                                   "c.relpersistence, 't' as relispopulated, "
4377                                                   "'d' AS relreplident, c.relpages, "
4378                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4379                                                   "d.refobjid AS owning_tab, "
4380                                                   "d.refobjsubid AS owning_col, "
4381                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4382                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4383                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4384                                                   "FROM pg_class c "
4385                                                   "LEFT JOIN pg_depend d ON "
4386                                                   "(c.relkind = '%c' AND "
4387                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4388                                                   "d.objsubid = 0 AND "
4389                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4390                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4391                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4392                                                   "ORDER BY c.oid",
4393                                                   username_subquery,
4394                                                   RELKIND_SEQUENCE,
4395                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4396                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4397                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4398         }
4399         else if (fout->remoteVersion >= 90000)
4400         {
4401                 /*
4402                  * Left join to pick up dependency info linking sequences to their
4403                  * owning column, if any (note this dependency is AUTO as of 8.2)
4404                  */
4405                 appendPQExpBuffer(query,
4406                                                   "SELECT c.tableoid, c.oid, c.relname, "
4407                                                   "c.relacl, c.relkind, c.relnamespace, "
4408                                                   "(%s c.relowner) AS rolname, "
4409                                                   "c.relchecks, c.relhastriggers, "
4410                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4411                                                   "c.relfrozenxid, tc.oid AS toid, "
4412                                                   "tc.relfrozenxid AS tfrozenxid, "
4413                                                   "'p' AS relpersistence, 't' as relispopulated, "
4414                                                   "'d' AS relreplident, c.relpages, "
4415                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4416                                                   "d.refobjid AS owning_tab, "
4417                                                   "d.refobjsubid AS owning_col, "
4418                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4419                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4420                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4421                                                   "FROM pg_class c "
4422                                                   "LEFT JOIN pg_depend d ON "
4423                                                   "(c.relkind = '%c' AND "
4424                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4425                                                   "d.objsubid = 0 AND "
4426                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4427                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4428                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4429                                                   "ORDER BY c.oid",
4430                                                   username_subquery,
4431                                                   RELKIND_SEQUENCE,
4432                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4433                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4434         }
4435         else if (fout->remoteVersion >= 80400)
4436         {
4437                 /*
4438                  * Left join to pick up dependency info linking sequences to their
4439                  * owning column, if any (note this dependency is AUTO as of 8.2)
4440                  */
4441                 appendPQExpBuffer(query,
4442                                                   "SELECT c.tableoid, c.oid, c.relname, "
4443                                                   "c.relacl, c.relkind, c.relnamespace, "
4444                                                   "(%s c.relowner) AS rolname, "
4445                                                   "c.relchecks, c.relhastriggers, "
4446                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4447                                                   "c.relfrozenxid, tc.oid AS toid, "
4448                                                   "tc.relfrozenxid AS tfrozenxid, "
4449                                                   "'p' AS relpersistence, 't' as relispopulated, "
4450                                                   "'d' AS relreplident, c.relpages, "
4451                                                   "NULL AS reloftype, "
4452                                                   "d.refobjid AS owning_tab, "
4453                                                   "d.refobjsubid AS owning_col, "
4454                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4455                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4456                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4457                                                   "FROM pg_class c "
4458                                                   "LEFT JOIN pg_depend d ON "
4459                                                   "(c.relkind = '%c' AND "
4460                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4461                                                   "d.objsubid = 0 AND "
4462                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4463                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4464                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4465                                                   "ORDER BY c.oid",
4466                                                   username_subquery,
4467                                                   RELKIND_SEQUENCE,
4468                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4469                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4470         }
4471         else if (fout->remoteVersion >= 80200)
4472         {
4473                 /*
4474                  * Left join to pick up dependency info linking sequences to their
4475                  * owning column, if any (note this dependency is AUTO as of 8.2)
4476                  */
4477                 appendPQExpBuffer(query,
4478                                                   "SELECT c.tableoid, c.oid, c.relname, "
4479                                                   "c.relacl, c.relkind, c.relnamespace, "
4480                                                   "(%s c.relowner) AS rolname, "
4481                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4482                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4483                                                   "c.relfrozenxid, tc.oid AS toid, "
4484                                                   "tc.relfrozenxid AS tfrozenxid, "
4485                                                   "'p' AS relpersistence, 't' as relispopulated, "
4486                                                   "'d' AS relreplident, c.relpages, "
4487                                                   "NULL AS reloftype, "
4488                                                   "d.refobjid AS owning_tab, "
4489                                                   "d.refobjsubid AS owning_col, "
4490                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4491                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4492                                                   "NULL AS toast_reloptions "
4493                                                   "FROM pg_class c "
4494                                                   "LEFT JOIN pg_depend d ON "
4495                                                   "(c.relkind = '%c' AND "
4496                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4497                                                   "d.objsubid = 0 AND "
4498                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4499                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4500                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4501                                                   "ORDER BY c.oid",
4502                                                   username_subquery,
4503                                                   RELKIND_SEQUENCE,
4504                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4505                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4506         }
4507         else if (fout->remoteVersion >= 80000)
4508         {
4509                 /*
4510                  * Left join to pick up dependency info linking sequences to their
4511                  * owning column, if any
4512                  */
4513                 appendPQExpBuffer(query,
4514                                                   "SELECT c.tableoid, c.oid, relname, "
4515                                                   "relacl, relkind, relnamespace, "
4516                                                   "(%s relowner) AS rolname, "
4517                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4518                                                   "relhasindex, relhasrules, relhasoids, "
4519                                                   "0 AS relfrozenxid, "
4520                                                   "0 AS toid, "
4521                                                   "0 AS tfrozenxid, "
4522                                                   "'p' AS relpersistence, 't' as relispopulated, "
4523                                                   "'d' AS relreplident, relpages, "
4524                                                   "NULL AS reloftype, "
4525                                                   "d.refobjid AS owning_tab, "
4526                                                   "d.refobjsubid AS owning_col, "
4527                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4528                                                   "NULL AS reloptions, "
4529                                                   "NULL AS toast_reloptions "
4530                                                   "FROM pg_class c "
4531                                                   "LEFT JOIN pg_depend d ON "
4532                                                   "(c.relkind = '%c' AND "
4533                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4534                                                   "d.objsubid = 0 AND "
4535                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4536                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4537                                                   "ORDER BY c.oid",
4538                                                   username_subquery,
4539                                                   RELKIND_SEQUENCE,
4540                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4541                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4542         }
4543         else if (fout->remoteVersion >= 70300)
4544         {
4545                 /*
4546                  * Left join to pick up dependency info linking sequences to their
4547                  * owning column, if any
4548                  */
4549                 appendPQExpBuffer(query,
4550                                                   "SELECT c.tableoid, c.oid, relname, "
4551                                                   "relacl, relkind, relnamespace, "
4552                                                   "(%s relowner) AS rolname, "
4553                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4554                                                   "relhasindex, relhasrules, relhasoids, "
4555                                                   "0 AS relfrozenxid, "
4556                                                   "0 AS toid, "
4557                                                   "0 AS tfrozenxid, "
4558                                                   "'p' AS relpersistence, 't' as relispopulated, "
4559                                                   "'d' AS relreplident, relpages, "
4560                                                   "NULL AS reloftype, "
4561                                                   "d.refobjid AS owning_tab, "
4562                                                   "d.refobjsubid AS owning_col, "
4563                                                   "NULL AS reltablespace, "
4564                                                   "NULL AS reloptions, "
4565                                                   "NULL AS toast_reloptions "
4566                                                   "FROM pg_class c "
4567                                                   "LEFT JOIN pg_depend d ON "
4568                                                   "(c.relkind = '%c' AND "
4569                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4570                                                   "d.objsubid = 0 AND "
4571                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4572                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4573                                                   "ORDER BY c.oid",
4574                                                   username_subquery,
4575                                                   RELKIND_SEQUENCE,
4576                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4577                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4578         }
4579         else if (fout->remoteVersion >= 70200)
4580         {
4581                 appendPQExpBuffer(query,
4582                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4583                                                   "0::oid AS relnamespace, "
4584                                                   "(%s relowner) AS rolname, "
4585                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4586                                                   "relhasindex, relhasrules, relhasoids, "
4587                                                   "0 AS relfrozenxid, "
4588                                                   "0 AS toid, "
4589                                                   "0 AS tfrozenxid, "
4590                                                   "'p' AS relpersistence, 't' as relispopulated, "
4591                                                   "'d' AS relreplident, relpages, "
4592                                                   "NULL AS reloftype, "
4593                                                   "NULL::oid AS owning_tab, "
4594                                                   "NULL::int4 AS owning_col, "
4595                                                   "NULL AS reltablespace, "
4596                                                   "NULL AS reloptions, "
4597                                                   "NULL AS toast_reloptions "
4598                                                   "FROM pg_class "
4599                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4600                                                   "ORDER BY oid",
4601                                                   username_subquery,
4602                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4603         }
4604         else if (fout->remoteVersion >= 70100)
4605         {
4606                 /* all tables have oids in 7.1 */
4607                 appendPQExpBuffer(query,
4608                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4609                                                   "0::oid AS relnamespace, "
4610                                                   "(%s relowner) AS rolname, "
4611                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4612                                                   "relhasindex, relhasrules, "
4613                                                   "'t'::bool AS relhasoids, "
4614                                                   "0 AS relfrozenxid, "
4615                                                   "0 AS toid, "
4616                                                   "0 AS tfrozenxid, "
4617                                                   "'p' AS relpersistence, 't' as relispopulated, "
4618                                                   "'d' AS relreplident, relpages, "
4619                                                   "NULL AS reloftype, "
4620                                                   "NULL::oid AS owning_tab, "
4621                                                   "NULL::int4 AS owning_col, "
4622                                                   "NULL AS reltablespace, "
4623                                                   "NULL AS reloptions, "
4624                                                   "NULL AS toast_reloptions "
4625                                                   "FROM pg_class "
4626                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4627                                                   "ORDER BY oid",
4628                                                   username_subquery,
4629                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4630         }
4631         else
4632         {
4633                 /*
4634                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4635                  * have a view by looking for a rule in pg_rewrite.
4636                  */
4637                 appendPQExpBuffer(query,
4638                                                   "SELECT "
4639                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4640                                                   "oid, relname, relacl, "
4641                                                   "CASE WHEN relhasrules and relkind = 'r' "
4642                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4643                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4644                                                   "THEN '%c'::\"char\" "
4645                                                   "ELSE relkind END AS relkind,"
4646                                                   "0::oid AS relnamespace, "
4647                                                   "(%s relowner) AS rolname, "
4648                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4649                                                   "relhasindex, relhasrules, "
4650                                                   "'t'::bool AS relhasoids, "
4651                                                   "0 as relfrozenxid, "
4652                                                   "0 AS toid, "
4653                                                   "0 AS tfrozenxid, "
4654                                                   "'p' AS relpersistence, 't' as relispopulated, "
4655                                                   "'d' AS relreplident, 0 AS relpages, "
4656                                                   "NULL AS reloftype, "
4657                                                   "NULL::oid AS owning_tab, "
4658                                                   "NULL::int4 AS owning_col, "
4659                                                   "NULL AS reltablespace, "
4660                                                   "NULL AS reloptions, "
4661                                                   "NULL AS toast_reloptions "
4662                                                   "FROM pg_class c "
4663                                                   "WHERE relkind IN ('%c', '%c') "
4664                                                   "ORDER BY oid",
4665                                                   RELKIND_VIEW,
4666                                                   username_subquery,
4667                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4668         }
4669
4670         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4671
4672         ntups = PQntuples(res);
4673
4674         *numTables = ntups;
4675
4676         /*
4677          * Extract data from result and lock dumpable tables.  We do the locking
4678          * before anything else, to minimize the window wherein a table could
4679          * disappear under us.
4680          *
4681          * Note that we have to save info about all tables here, even when dumping
4682          * only one, because we don't yet know which tables might be inheritance
4683          * ancestors of the target table.
4684          */
4685         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
4686
4687         i_reltableoid = PQfnumber(res, "tableoid");
4688         i_reloid = PQfnumber(res, "oid");
4689         i_relname = PQfnumber(res, "relname");
4690         i_relnamespace = PQfnumber(res, "relnamespace");
4691         i_relacl = PQfnumber(res, "relacl");
4692         i_relkind = PQfnumber(res, "relkind");
4693         i_rolname = PQfnumber(res, "rolname");
4694         i_relchecks = PQfnumber(res, "relchecks");
4695         i_relhastriggers = PQfnumber(res, "relhastriggers");
4696         i_relhasindex = PQfnumber(res, "relhasindex");
4697         i_relhasrules = PQfnumber(res, "relhasrules");
4698         i_relhasoids = PQfnumber(res, "relhasoids");
4699         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4700         i_toastoid = PQfnumber(res, "toid");
4701         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4702         i_relpersistence = PQfnumber(res, "relpersistence");
4703         i_relispopulated = PQfnumber(res, "relispopulated");
4704         i_relreplident = PQfnumber(res, "relreplident");
4705         i_relpages = PQfnumber(res, "relpages");
4706         i_owning_tab = PQfnumber(res, "owning_tab");
4707         i_owning_col = PQfnumber(res, "owning_col");
4708         i_reltablespace = PQfnumber(res, "reltablespace");
4709         i_reloptions = PQfnumber(res, "reloptions");
4710         i_checkoption = PQfnumber(res, "checkoption");
4711         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4712         i_reloftype = PQfnumber(res, "reloftype");
4713
4714         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4715         {
4716                 /*
4717                  * Arrange to fail instead of waiting forever for a table lock.
4718                  *
4719                  * NB: this coding assumes that the only queries issued within the
4720                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4721                  * applied to other things too.
4722                  */
4723                 resetPQExpBuffer(query);
4724                 appendPQExpBuffer(query, "SET statement_timeout = ");
4725                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4726                 ExecuteSqlStatement(fout, query->data);
4727         }
4728
4729         for (i = 0; i < ntups; i++)
4730         {
4731                 tblinfo[i].dobj.objType = DO_TABLE;
4732                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4733                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4734                 AssignDumpId(&tblinfo[i].dobj);
4735                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4736                 tblinfo[i].dobj.namespace =
4737                         findNamespace(fout,
4738                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4739                                                   tblinfo[i].dobj.catId.oid);
4740                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4741                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4742                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4743                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4744                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4745                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4746                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4747                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4748                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
4749                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
4750                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
4751                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4752                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4753                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4754                 if (PQgetisnull(res, i, i_reloftype))
4755                         tblinfo[i].reloftype = NULL;
4756                 else
4757                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4758                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4759                 if (PQgetisnull(res, i, i_owning_tab))
4760                 {
4761                         tblinfo[i].owning_tab = InvalidOid;
4762                         tblinfo[i].owning_col = 0;
4763                 }
4764                 else
4765                 {
4766                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4767                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4768                 }
4769                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4770                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4771                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
4772                         tblinfo[i].checkoption = NULL;
4773                 else
4774                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
4775                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4776
4777                 /* other fields were zeroed above */
4778
4779                 /*
4780                  * Decide whether we want to dump this table.
4781                  */
4782                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4783                         tblinfo[i].dobj.dump = false;
4784                 else
4785                         selectDumpableTable(&tblinfo[i]);
4786                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4787
4788                 /*
4789                  * Read-lock target tables to make sure they aren't DROPPED or altered
4790                  * in schema before we get around to dumping them.
4791                  *
4792                  * Note that we don't explicitly lock parents of the target tables; we
4793                  * assume our lock on the child is enough to prevent schema
4794                  * alterations to parent tables.
4795                  *
4796                  * NOTE: it'd be kinda nice to lock other relations too, not only
4797                  * plain tables, but the backend doesn't presently allow that.
4798                  */
4799                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4800                 {
4801                         resetPQExpBuffer(query);
4802                         appendPQExpBuffer(query,
4803                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4804                                                           fmtQualifiedId(fout->remoteVersion,
4805                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4806                                                                                          tblinfo[i].dobj.name));
4807                         ExecuteSqlStatement(fout, query->data);
4808                 }
4809
4810                 /* Emit notice if join for owner failed */
4811                 if (strlen(tblinfo[i].rolname) == 0)
4812                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4813                                           tblinfo[i].dobj.name);
4814         }
4815
4816         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4817         {
4818                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4819         }
4820
4821         PQclear(res);
4822
4823         destroyPQExpBuffer(query);
4824
4825         return tblinfo;
4826 }
4827
4828 /*
4829  * getOwnedSeqs
4830  *        identify owned sequences and mark them as dumpable if owning table is
4831  *
4832  * We used to do this in getTables(), but it's better to do it after the
4833  * index used by findTableByOid() has been set up.
4834  */
4835 void
4836 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4837 {
4838         int                     i;
4839
4840         /*
4841          * Force sequences that are "owned" by table columns to be dumped whenever
4842          * their owning table is being dumped.
4843          */
4844         for (i = 0; i < numTables; i++)
4845         {
4846                 TableInfo  *seqinfo = &tblinfo[i];
4847                 TableInfo  *owning_tab;
4848
4849                 if (!OidIsValid(seqinfo->owning_tab))
4850                         continue;                       /* not an owned sequence */
4851                 if (seqinfo->dobj.dump)
4852                         continue;                       /* no need to search */
4853                 owning_tab = findTableByOid(seqinfo->owning_tab);
4854                 if (owning_tab && owning_tab->dobj.dump)
4855                 {
4856                         seqinfo->interesting = true;
4857                         seqinfo->dobj.dump = true;
4858                 }
4859         }
4860 }
4861
4862 /*
4863  * getInherits
4864  *        read all the inheritance information
4865  * from the system catalogs return them in the InhInfo* structure
4866  *
4867  * numInherits is set to the number of pairs read in
4868  */
4869 InhInfo *
4870 getInherits(Archive *fout, int *numInherits)
4871 {
4872         PGresult   *res;
4873         int                     ntups;
4874         int                     i;
4875         PQExpBuffer query = createPQExpBuffer();
4876         InhInfo    *inhinfo;
4877
4878         int                     i_inhrelid;
4879         int                     i_inhparent;
4880
4881         /* Make sure we are in proper schema */
4882         selectSourceSchema(fout, "pg_catalog");
4883
4884         /* find all the inheritance information */
4885
4886         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4887
4888         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4889
4890         ntups = PQntuples(res);
4891
4892         *numInherits = ntups;
4893
4894         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4895
4896         i_inhrelid = PQfnumber(res, "inhrelid");
4897         i_inhparent = PQfnumber(res, "inhparent");
4898
4899         for (i = 0; i < ntups; i++)
4900         {
4901                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4902                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4903         }
4904
4905         PQclear(res);
4906
4907         destroyPQExpBuffer(query);
4908
4909         return inhinfo;
4910 }
4911
4912 /*
4913  * getIndexes
4914  *        get information about every index on a dumpable table
4915  *
4916  * Note: index data is not returned directly to the caller, but it
4917  * does get entered into the DumpableObject tables.
4918  */
4919 void
4920 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4921 {
4922         int                     i,
4923                                 j;
4924         PQExpBuffer query = createPQExpBuffer();
4925         PGresult   *res;
4926         IndxInfo   *indxinfo;
4927         ConstraintInfo *constrinfo;
4928         int                     i_tableoid,
4929                                 i_oid,
4930                                 i_indexname,
4931                                 i_indexdef,
4932                                 i_indnkeys,
4933                                 i_indkey,
4934                                 i_indisclustered,
4935                                 i_indisreplident,
4936                                 i_contype,
4937                                 i_conname,
4938                                 i_condeferrable,
4939                                 i_condeferred,
4940                                 i_contableoid,
4941                                 i_conoid,
4942                                 i_condef,
4943                                 i_tablespace,
4944                                 i_options,
4945                                 i_relpages;
4946         int                     ntups;
4947
4948         for (i = 0; i < numTables; i++)
4949         {
4950                 TableInfo  *tbinfo = &tblinfo[i];
4951
4952                 /* Only plain tables and materialized views have indexes. */
4953                 if (tbinfo->relkind != RELKIND_RELATION &&
4954                         tbinfo->relkind != RELKIND_MATVIEW)
4955                         continue;
4956                 if (!tbinfo->hasindex)
4957                         continue;
4958
4959                 /* Ignore indexes of tables not to be dumped */
4960                 if (!tbinfo->dobj.dump)
4961                         continue;
4962
4963                 if (g_verbose)
4964                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4965                                           tbinfo->dobj.name);
4966
4967                 /* Make sure we are in proper schema so indexdef is right */
4968                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4969
4970                 /*
4971                  * The point of the messy-looking outer join is to find a constraint
4972                  * that is related by an internal dependency link to the index. If we
4973                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4974                  * assume an index won't have more than one internal dependency.
4975                  *
4976                  * As of 9.0 we don't need to look at pg_depend but can check for a
4977                  * match to pg_constraint.conindid.  The check on conrelid is
4978                  * redundant but useful because that column is indexed while conindid
4979                  * is not.
4980                  */
4981                 resetPQExpBuffer(query);
4982                 if (fout->remoteVersion >= 90400)
4983                 {
4984                         /*
4985                          * the test on indisready is necessary in 9.2, and harmless in
4986                          * earlier/later versions
4987                          */
4988                         appendPQExpBuffer(query,
4989                                                           "SELECT t.tableoid, t.oid, "
4990                                                           "t.relname AS indexname, "
4991                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4992                                                           "t.relnatts AS indnkeys, "
4993                                                           "i.indkey, i.indisclustered, "
4994                                                           "i.indisreplident, t.relpages, "
4995                                                           "c.contype, c.conname, "
4996                                                           "c.condeferrable, c.condeferred, "
4997                                                           "c.tableoid AS contableoid, "
4998                                                           "c.oid AS conoid, "
4999                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5000                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5001                                                         "array_to_string(t.reloptions, ', ') AS options "
5002                                                           "FROM pg_catalog.pg_index i "
5003                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5004                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5005                                                           "ON (i.indrelid = c.conrelid AND "
5006                                                           "i.indexrelid = c.conindid AND "
5007                                                           "c.contype IN ('p','u','x')) "
5008                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5009                                                           "AND i.indisvalid AND i.indisready "
5010                                                           "ORDER BY indexname",
5011                                                           tbinfo->dobj.catId.oid);
5012                 }
5013                 else if (fout->remoteVersion >= 90000)
5014                 {
5015                         /*
5016                          * the test on indisready is necessary in 9.2, and harmless in
5017                          * earlier/later versions
5018                          */
5019                         appendPQExpBuffer(query,
5020                                                           "SELECT t.tableoid, t.oid, "
5021                                                           "t.relname AS indexname, "
5022                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5023                                                           "t.relnatts AS indnkeys, "
5024                                                           "i.indkey, i.indisclustered, "
5025                                                           "false AS indisreplident, t.relpages, "
5026                                                           "c.contype, c.conname, "
5027                                                           "c.condeferrable, c.condeferred, "
5028                                                           "c.tableoid AS contableoid, "
5029                                                           "c.oid AS conoid, "
5030                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5031                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5032                                                         "array_to_string(t.reloptions, ', ') AS options "
5033                                                           "FROM pg_catalog.pg_index i "
5034                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5035                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5036                                                           "ON (i.indrelid = c.conrelid AND "
5037                                                           "i.indexrelid = c.conindid AND "
5038                                                           "c.contype IN ('p','u','x')) "
5039                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5040                                                           "AND i.indisvalid AND i.indisready "
5041                                                           "ORDER BY indexname",
5042                                                           tbinfo->dobj.catId.oid);
5043                 }
5044                 else if (fout->remoteVersion >= 80200)
5045                 {
5046                         appendPQExpBuffer(query,
5047                                                           "SELECT t.tableoid, t.oid, "
5048                                                           "t.relname AS indexname, "
5049                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5050                                                           "t.relnatts AS indnkeys, "
5051                                                           "i.indkey, i.indisclustered, "
5052                                                           "false AS indisreplident, t.relpages, "
5053                                                           "c.contype, c.conname, "
5054                                                           "c.condeferrable, c.condeferred, "
5055                                                           "c.tableoid AS contableoid, "
5056                                                           "c.oid AS conoid, "
5057                                                           "null AS condef, "
5058                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5059                                                         "array_to_string(t.reloptions, ', ') AS options "
5060                                                           "FROM pg_catalog.pg_index i "
5061                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5062                                                           "LEFT JOIN pg_catalog.pg_depend d "
5063                                                           "ON (d.classid = t.tableoid "
5064                                                           "AND d.objid = t.oid "
5065                                                           "AND d.deptype = 'i') "
5066                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5067                                                           "ON (d.refclassid = c.tableoid "
5068                                                           "AND d.refobjid = c.oid) "
5069                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5070                                                           "AND i.indisvalid "
5071                                                           "ORDER BY indexname",
5072                                                           tbinfo->dobj.catId.oid);
5073                 }
5074                 else if (fout->remoteVersion >= 80000)
5075                 {
5076                         appendPQExpBuffer(query,
5077                                                           "SELECT t.tableoid, t.oid, "
5078                                                           "t.relname AS indexname, "
5079                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5080                                                           "t.relnatts AS indnkeys, "
5081                                                           "i.indkey, i.indisclustered, "
5082                                                           "false AS indisreplident, t.relpages, "
5083                                                           "c.contype, c.conname, "
5084                                                           "c.condeferrable, c.condeferred, "
5085                                                           "c.tableoid AS contableoid, "
5086                                                           "c.oid AS conoid, "
5087                                                           "null AS condef, "
5088                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5089                                                           "null AS options "
5090                                                           "FROM pg_catalog.pg_index i "
5091                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5092                                                           "LEFT JOIN pg_catalog.pg_depend d "
5093                                                           "ON (d.classid = t.tableoid "
5094                                                           "AND d.objid = t.oid "
5095                                                           "AND d.deptype = 'i') "
5096                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5097                                                           "ON (d.refclassid = c.tableoid "
5098                                                           "AND d.refobjid = c.oid) "
5099                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5100                                                           "ORDER BY indexname",
5101                                                           tbinfo->dobj.catId.oid);
5102                 }
5103                 else if (fout->remoteVersion >= 70300)
5104                 {
5105                         appendPQExpBuffer(query,
5106                                                           "SELECT t.tableoid, t.oid, "
5107                                                           "t.relname AS indexname, "
5108                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5109                                                           "t.relnatts AS indnkeys, "
5110                                                           "i.indkey, i.indisclustered, "
5111                                                           "false AS indisreplident, t.relpages, "
5112                                                           "c.contype, c.conname, "
5113                                                           "c.condeferrable, c.condeferred, "
5114                                                           "c.tableoid AS contableoid, "
5115                                                           "c.oid AS conoid, "
5116                                                           "null AS condef, "
5117                                                           "NULL AS tablespace, "
5118                                                           "null AS options "
5119                                                           "FROM pg_catalog.pg_index i "
5120                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5121                                                           "LEFT JOIN pg_catalog.pg_depend d "
5122                                                           "ON (d.classid = t.tableoid "
5123                                                           "AND d.objid = t.oid "
5124                                                           "AND d.deptype = 'i') "
5125                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5126                                                           "ON (d.refclassid = c.tableoid "
5127                                                           "AND d.refobjid = c.oid) "
5128                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5129                                                           "ORDER BY indexname",
5130                                                           tbinfo->dobj.catId.oid);
5131                 }
5132                 else if (fout->remoteVersion >= 70100)
5133                 {
5134                         appendPQExpBuffer(query,
5135                                                           "SELECT t.tableoid, t.oid, "
5136                                                           "t.relname AS indexname, "
5137                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5138                                                           "t.relnatts AS indnkeys, "
5139                                                           "i.indkey, false AS indisclustered, "
5140                                                           "false AS indisreplident, t.relpages, "
5141                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5142                                                           "ELSE '0'::char END AS contype, "
5143                                                           "t.relname AS conname, "
5144                                                           "false AS condeferrable, "
5145                                                           "false AS condeferred, "
5146                                                           "0::oid AS contableoid, "
5147                                                           "t.oid AS conoid, "
5148                                                           "null AS condef, "
5149                                                           "NULL AS tablespace, "
5150                                                           "null AS options "
5151                                                           "FROM pg_index i, pg_class t "
5152                                                           "WHERE t.oid = i.indexrelid "
5153                                                           "AND i.indrelid = '%u'::oid "
5154                                                           "ORDER BY indexname",
5155                                                           tbinfo->dobj.catId.oid);
5156                 }
5157                 else
5158                 {
5159                         appendPQExpBuffer(query,
5160                                                           "SELECT "
5161                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5162                                                           "t.oid, "
5163                                                           "t.relname AS indexname, "
5164                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5165                                                           "t.relnatts AS indnkeys, "
5166                                                           "i.indkey, false AS indisclustered, "
5167                                                           "false AS indisreplident, t.relpages, "
5168                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5169                                                           "ELSE '0'::char END AS contype, "
5170                                                           "t.relname AS conname, "
5171                                                           "false AS condeferrable, "
5172                                                           "false AS condeferred, "
5173                                                           "0::oid AS contableoid, "
5174                                                           "t.oid AS conoid, "
5175                                                           "null AS condef, "
5176                                                           "NULL AS tablespace, "
5177                                                           "null AS options "
5178                                                           "FROM pg_index i, pg_class t "
5179                                                           "WHERE t.oid = i.indexrelid "
5180                                                           "AND i.indrelid = '%u'::oid "
5181                                                           "ORDER BY indexname",
5182                                                           tbinfo->dobj.catId.oid);
5183                 }
5184
5185                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5186
5187                 ntups = PQntuples(res);
5188
5189                 i_tableoid = PQfnumber(res, "tableoid");
5190                 i_oid = PQfnumber(res, "oid");
5191                 i_indexname = PQfnumber(res, "indexname");
5192                 i_indexdef = PQfnumber(res, "indexdef");
5193                 i_indnkeys = PQfnumber(res, "indnkeys");
5194                 i_indkey = PQfnumber(res, "indkey");
5195                 i_indisclustered = PQfnumber(res, "indisclustered");
5196                 i_indisreplident = PQfnumber(res, "indisreplident");
5197                 i_relpages = PQfnumber(res, "relpages");
5198                 i_contype = PQfnumber(res, "contype");
5199                 i_conname = PQfnumber(res, "conname");
5200                 i_condeferrable = PQfnumber(res, "condeferrable");
5201                 i_condeferred = PQfnumber(res, "condeferred");
5202                 i_contableoid = PQfnumber(res, "contableoid");
5203                 i_conoid = PQfnumber(res, "conoid");
5204                 i_condef = PQfnumber(res, "condef");
5205                 i_tablespace = PQfnumber(res, "tablespace");
5206                 i_options = PQfnumber(res, "options");
5207
5208                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5209                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5210
5211                 for (j = 0; j < ntups; j++)
5212                 {
5213                         char            contype;
5214
5215                         indxinfo[j].dobj.objType = DO_INDEX;
5216                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5217                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5218                         AssignDumpId(&indxinfo[j].dobj);
5219                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5220                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5221                         indxinfo[j].indextable = tbinfo;
5222                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5223                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5224                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5225                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5226
5227                         /*
5228                          * In pre-7.4 releases, indkeys may contain more entries than
5229                          * indnkeys says (since indnkeys will be 1 for a functional
5230                          * index).      We don't actually care about this case since we don't
5231                          * examine indkeys except for indexes associated with PRIMARY and
5232                          * UNIQUE constraints, which are never functional indexes. But we
5233                          * have to allocate enough space to keep parseOidArray from
5234                          * complaining.
5235                          */
5236                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5237                         parseOidArray(PQgetvalue(res, j, i_indkey),
5238                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5239                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5240                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
5241                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5242                         contype = *(PQgetvalue(res, j, i_contype));
5243
5244                         if (contype == 'p' || contype == 'u' || contype == 'x')
5245                         {
5246                                 /*
5247                                  * If we found a constraint matching the index, create an
5248                                  * entry for it.
5249                                  *
5250                                  * In a pre-7.3 database, we take this path iff the index was
5251                                  * marked indisprimary.
5252                                  */
5253                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5254                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5255                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5256                                 AssignDumpId(&constrinfo[j].dobj);
5257                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5258                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5259                                 constrinfo[j].contable = tbinfo;
5260                                 constrinfo[j].condomain = NULL;
5261                                 constrinfo[j].contype = contype;
5262                                 if (contype == 'x')
5263                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5264                                 else
5265                                         constrinfo[j].condef = NULL;
5266                                 constrinfo[j].confrelid = InvalidOid;
5267                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5268                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5269                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5270                                 constrinfo[j].conislocal = true;
5271                                 constrinfo[j].separate = true;
5272
5273                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5274
5275                                 /* If pre-7.3 DB, better make sure table comes first */
5276                                 addObjectDependency(&constrinfo[j].dobj,
5277                                                                         tbinfo->dobj.dumpId);
5278                         }
5279                         else
5280                         {
5281                                 /* Plain secondary index */
5282                                 indxinfo[j].indexconstraint = 0;
5283                         }
5284                 }
5285
5286                 PQclear(res);
5287         }
5288
5289         destroyPQExpBuffer(query);
5290 }
5291
5292 /*
5293  * getConstraints
5294  *
5295  * Get info about constraints on dumpable tables.
5296  *
5297  * Currently handles foreign keys only.
5298  * Unique and primary key constraints are handled with indexes,
5299  * while check constraints are processed in getTableAttrs().
5300  */
5301 void
5302 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5303 {
5304         int                     i,
5305                                 j;
5306         ConstraintInfo *constrinfo;
5307         PQExpBuffer query;
5308         PGresult   *res;
5309         int                     i_contableoid,
5310                                 i_conoid,
5311                                 i_conname,
5312                                 i_confrelid,
5313                                 i_condef;
5314         int                     ntups;
5315
5316         /* pg_constraint was created in 7.3, so nothing to do if older */
5317         if (fout->remoteVersion < 70300)
5318                 return;
5319
5320         query = createPQExpBuffer();
5321
5322         for (i = 0; i < numTables; i++)
5323         {
5324                 TableInfo  *tbinfo = &tblinfo[i];
5325
5326                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5327                         continue;
5328
5329                 if (g_verbose)
5330                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
5331                                           tbinfo->dobj.name);
5332
5333                 /*
5334                  * select table schema to ensure constraint expr is qualified if
5335                  * needed
5336                  */
5337                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5338
5339                 resetPQExpBuffer(query);
5340                 appendPQExpBuffer(query,
5341                                                   "SELECT tableoid, oid, conname, confrelid, "
5342                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5343                                                   "FROM pg_catalog.pg_constraint "
5344                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5345                                                   "AND contype = 'f'",
5346                                                   tbinfo->dobj.catId.oid);
5347                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5348
5349                 ntups = PQntuples(res);
5350
5351                 i_contableoid = PQfnumber(res, "tableoid");
5352                 i_conoid = PQfnumber(res, "oid");
5353                 i_conname = PQfnumber(res, "conname");
5354                 i_confrelid = PQfnumber(res, "confrelid");
5355                 i_condef = PQfnumber(res, "condef");
5356
5357                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5358
5359                 for (j = 0; j < ntups; j++)
5360                 {
5361                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5362                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5363                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5364                         AssignDumpId(&constrinfo[j].dobj);
5365                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5366                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5367                         constrinfo[j].contable = tbinfo;
5368                         constrinfo[j].condomain = NULL;
5369                         constrinfo[j].contype = 'f';
5370                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5371                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5372                         constrinfo[j].conindex = 0;
5373                         constrinfo[j].condeferrable = false;
5374                         constrinfo[j].condeferred = false;
5375                         constrinfo[j].conislocal = true;
5376                         constrinfo[j].separate = true;
5377                 }
5378
5379                 PQclear(res);
5380         }
5381
5382         destroyPQExpBuffer(query);
5383 }
5384
5385 /*
5386  * getDomainConstraints
5387  *
5388  * Get info about constraints on a domain.
5389  */
5390 static void
5391 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5392 {
5393         int                     i;
5394         ConstraintInfo *constrinfo;
5395         PQExpBuffer query;
5396         PGresult   *res;
5397         int                     i_tableoid,
5398                                 i_oid,
5399                                 i_conname,
5400                                 i_consrc;
5401         int                     ntups;
5402
5403         /* pg_constraint was created in 7.3, so nothing to do if older */
5404         if (fout->remoteVersion < 70300)
5405                 return;
5406
5407         /*
5408          * select appropriate schema to ensure names in constraint are properly
5409          * qualified
5410          */
5411         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5412
5413         query = createPQExpBuffer();
5414
5415         if (fout->remoteVersion >= 90100)
5416                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5417                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5418                                                   "convalidated "
5419                                                   "FROM pg_catalog.pg_constraint "
5420                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5421                                                   "ORDER BY conname",
5422                                                   tyinfo->dobj.catId.oid);
5423
5424         else if (fout->remoteVersion >= 70400)
5425                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5426                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5427                                                   "true as convalidated "
5428                                                   "FROM pg_catalog.pg_constraint "
5429                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5430                                                   "ORDER BY conname",
5431                                                   tyinfo->dobj.catId.oid);
5432         else
5433                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5434                                                   "'CHECK (' || consrc || ')' AS consrc, "
5435                                                   "true as convalidated "
5436                                                   "FROM pg_catalog.pg_constraint "
5437                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5438                                                   "ORDER BY conname",
5439                                                   tyinfo->dobj.catId.oid);
5440
5441         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5442
5443         ntups = PQntuples(res);
5444
5445         i_tableoid = PQfnumber(res, "tableoid");
5446         i_oid = PQfnumber(res, "oid");
5447         i_conname = PQfnumber(res, "conname");
5448         i_consrc = PQfnumber(res, "consrc");
5449
5450         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5451
5452         tyinfo->nDomChecks = ntups;
5453         tyinfo->domChecks = constrinfo;
5454
5455         for (i = 0; i < ntups; i++)
5456         {
5457                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5458
5459                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5460                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5461                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5462                 AssignDumpId(&constrinfo[i].dobj);
5463                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5464                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5465                 constrinfo[i].contable = NULL;
5466                 constrinfo[i].condomain = tyinfo;
5467                 constrinfo[i].contype = 'c';
5468                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5469                 constrinfo[i].confrelid = InvalidOid;
5470                 constrinfo[i].conindex = 0;
5471                 constrinfo[i].condeferrable = false;
5472                 constrinfo[i].condeferred = false;
5473                 constrinfo[i].conislocal = true;
5474
5475                 constrinfo[i].separate = !validated;
5476
5477                 /*
5478                  * Make the domain depend on the constraint, ensuring it won't be
5479                  * output till any constraint dependencies are OK.      If the constraint
5480                  * has not been validated, it's going to be dumped after the domain
5481                  * anyway, so this doesn't matter.
5482                  */
5483                 if (validated)
5484                         addObjectDependency(&tyinfo->dobj,
5485                                                                 constrinfo[i].dobj.dumpId);
5486         }
5487
5488         PQclear(res);
5489
5490         destroyPQExpBuffer(query);
5491 }
5492
5493 /*
5494  * getRules
5495  *        get basic information about every rule in the system
5496  *
5497  * numRules is set to the number of rules read in
5498  */
5499 RuleInfo *
5500 getRules(Archive *fout, int *numRules)
5501 {
5502         PGresult   *res;
5503         int                     ntups;
5504         int                     i;
5505         PQExpBuffer query = createPQExpBuffer();
5506         RuleInfo   *ruleinfo;
5507         int                     i_tableoid;
5508         int                     i_oid;
5509         int                     i_rulename;
5510         int                     i_ruletable;
5511         int                     i_ev_type;
5512         int                     i_is_instead;
5513         int                     i_ev_enabled;
5514
5515         /* Make sure we are in proper schema */
5516         selectSourceSchema(fout, "pg_catalog");
5517
5518         if (fout->remoteVersion >= 80300)
5519         {
5520                 appendPQExpBuffer(query, "SELECT "
5521                                                   "tableoid, oid, rulename, "
5522                                                   "ev_class AS ruletable, ev_type, is_instead, "
5523                                                   "ev_enabled "
5524                                                   "FROM pg_rewrite "
5525                                                   "ORDER BY oid");
5526         }
5527         else if (fout->remoteVersion >= 70100)
5528         {
5529                 appendPQExpBuffer(query, "SELECT "
5530                                                   "tableoid, oid, rulename, "
5531                                                   "ev_class AS ruletable, ev_type, is_instead, "
5532                                                   "'O'::char AS ev_enabled "
5533                                                   "FROM pg_rewrite "
5534                                                   "ORDER BY oid");
5535         }
5536         else
5537         {
5538                 appendPQExpBuffer(query, "SELECT "
5539                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5540                                                   "oid, rulename, "
5541                                                   "ev_class AS ruletable, ev_type, is_instead, "
5542                                                   "'O'::char AS ev_enabled "
5543                                                   "FROM pg_rewrite "
5544                                                   "ORDER BY oid");
5545         }
5546
5547         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5548
5549         ntups = PQntuples(res);
5550
5551         *numRules = ntups;
5552
5553         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5554
5555         i_tableoid = PQfnumber(res, "tableoid");
5556         i_oid = PQfnumber(res, "oid");
5557         i_rulename = PQfnumber(res, "rulename");
5558         i_ruletable = PQfnumber(res, "ruletable");
5559         i_ev_type = PQfnumber(res, "ev_type");
5560         i_is_instead = PQfnumber(res, "is_instead");
5561         i_ev_enabled = PQfnumber(res, "ev_enabled");
5562
5563         for (i = 0; i < ntups; i++)
5564         {
5565                 Oid                     ruletableoid;
5566
5567                 ruleinfo[i].dobj.objType = DO_RULE;
5568                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5569                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5570                 AssignDumpId(&ruleinfo[i].dobj);
5571                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5572                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5573                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5574                 if (ruleinfo[i].ruletable == NULL)
5575                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5576                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5577                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5578                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5579                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5580                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5581                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5582                 if (ruleinfo[i].ruletable)
5583                 {
5584                         /*
5585                          * If the table is a view or materialized view, force its ON
5586                          * SELECT rule to be sorted before the view itself --- this
5587                          * ensures that any dependencies for the rule affect the table's
5588                          * positioning. Other rules are forced to appear after their
5589                          * table.
5590                          */
5591                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5592                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5593                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5594                         {
5595                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5596                                                                         ruleinfo[i].dobj.dumpId);
5597                                 /* We'll merge the rule into CREATE VIEW, if possible */
5598                                 ruleinfo[i].separate = false;
5599                         }
5600                         else
5601                         {
5602                                 addObjectDependency(&ruleinfo[i].dobj,
5603                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5604                                 ruleinfo[i].separate = true;
5605                         }
5606                 }
5607                 else
5608                         ruleinfo[i].separate = true;
5609
5610                 /*
5611                  * If we're forced to break a dependency loop by dumping a view as a
5612                  * table and separate _RETURN rule, we'll move the view's reloptions
5613                  * to the rule.  (This is necessary because tables and views have
5614                  * different valid reloptions, so we can't apply the options until the
5615                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5616                  * NULL.
5617                  */
5618                 ruleinfo[i].reloptions = NULL;
5619         }
5620
5621         PQclear(res);
5622
5623         destroyPQExpBuffer(query);
5624
5625         return ruleinfo;
5626 }
5627
5628 /*
5629  * getTriggers
5630  *        get information about every trigger on a dumpable table
5631  *
5632  * Note: trigger data is not returned directly to the caller, but it
5633  * does get entered into the DumpableObject tables.
5634  */
5635 void
5636 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5637 {
5638         int                     i,
5639                                 j;
5640         PQExpBuffer query = createPQExpBuffer();
5641         PGresult   *res;
5642         TriggerInfo *tginfo;
5643         int                     i_tableoid,
5644                                 i_oid,
5645                                 i_tgname,
5646                                 i_tgfname,
5647                                 i_tgtype,
5648                                 i_tgnargs,
5649                                 i_tgargs,
5650                                 i_tgisconstraint,
5651                                 i_tgconstrname,
5652                                 i_tgconstrrelid,
5653                                 i_tgconstrrelname,
5654                                 i_tgenabled,
5655                                 i_tgdeferrable,
5656                                 i_tginitdeferred,
5657                                 i_tgdef;
5658         int                     ntups;
5659
5660         for (i = 0; i < numTables; i++)
5661         {
5662                 TableInfo  *tbinfo = &tblinfo[i];
5663
5664                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5665                         continue;
5666
5667                 if (g_verbose)
5668                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5669                                           tbinfo->dobj.name);
5670
5671                 /*
5672                  * select table schema to ensure regproc name is qualified if needed
5673                  */
5674                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5675
5676                 resetPQExpBuffer(query);
5677                 if (fout->remoteVersion >= 90000)
5678                 {
5679                         /*
5680                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5681                          * could result in non-forward-compatible dumps of WHEN clauses
5682                          * due to under-parenthesization.
5683                          */
5684                         appendPQExpBuffer(query,
5685                                                           "SELECT tgname, "
5686                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5687                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5688                                                           "tgenabled, tableoid, oid "
5689                                                           "FROM pg_catalog.pg_trigger t "
5690                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5691                                                           "AND NOT tgisinternal",
5692                                                           tbinfo->dobj.catId.oid);
5693                 }
5694                 else if (fout->remoteVersion >= 80300)
5695                 {
5696                         /*
5697                          * We ignore triggers that are tied to a foreign-key constraint
5698                          */
5699                         appendPQExpBuffer(query,
5700                                                           "SELECT tgname, "
5701                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5702                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5703                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5704                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5705                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5706                                                           "FROM pg_catalog.pg_trigger t "
5707                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5708                                                           "AND tgconstraint = 0",
5709                                                           tbinfo->dobj.catId.oid);
5710                 }
5711                 else if (fout->remoteVersion >= 70300)
5712                 {
5713                         /*
5714                          * We ignore triggers that are tied to a foreign-key constraint,
5715                          * but in these versions we have to grovel through pg_constraint
5716                          * to find out
5717                          */
5718                         appendPQExpBuffer(query,
5719                                                           "SELECT tgname, "
5720                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5721                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5722                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5723                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5724                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5725                                                           "FROM pg_catalog.pg_trigger t "
5726                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5727                                                           "AND (NOT tgisconstraint "
5728                                                           " OR NOT EXISTS"
5729                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5730                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5731                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5732                                                           tbinfo->dobj.catId.oid);
5733                 }
5734                 else if (fout->remoteVersion >= 70100)
5735                 {
5736                         appendPQExpBuffer(query,
5737                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5738                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5739                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5740                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5741                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5742                                                           "             AS tgconstrrelname "
5743                                                           "FROM pg_trigger "
5744                                                           "WHERE tgrelid = '%u'::oid",
5745                                                           tbinfo->dobj.catId.oid);
5746                 }
5747                 else
5748                 {
5749                         appendPQExpBuffer(query,
5750                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5751                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5752                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5753                                                           "tgconstrrelid, tginitdeferred, "
5754                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5755                                                           "oid, "
5756                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5757                                                           "             AS tgconstrrelname "
5758                                                           "FROM pg_trigger "
5759                                                           "WHERE tgrelid = '%u'::oid",
5760                                                           tbinfo->dobj.catId.oid);
5761                 }
5762                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5763
5764                 ntups = PQntuples(res);
5765
5766                 i_tableoid = PQfnumber(res, "tableoid");
5767                 i_oid = PQfnumber(res, "oid");
5768                 i_tgname = PQfnumber(res, "tgname");
5769                 i_tgfname = PQfnumber(res, "tgfname");
5770                 i_tgtype = PQfnumber(res, "tgtype");
5771                 i_tgnargs = PQfnumber(res, "tgnargs");
5772                 i_tgargs = PQfnumber(res, "tgargs");
5773                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5774                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5775                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5776                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5777                 i_tgenabled = PQfnumber(res, "tgenabled");
5778                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5779                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5780                 i_tgdef = PQfnumber(res, "tgdef");
5781
5782                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5783
5784                 for (j = 0; j < ntups; j++)
5785                 {
5786                         tginfo[j].dobj.objType = DO_TRIGGER;
5787                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5788                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5789                         AssignDumpId(&tginfo[j].dobj);
5790                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5791                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5792                         tginfo[j].tgtable = tbinfo;
5793                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5794                         if (i_tgdef >= 0)
5795                         {
5796                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5797
5798                                 /* remaining fields are not valid if we have tgdef */
5799                                 tginfo[j].tgfname = NULL;
5800                                 tginfo[j].tgtype = 0;
5801                                 tginfo[j].tgnargs = 0;
5802                                 tginfo[j].tgargs = NULL;
5803                                 tginfo[j].tgisconstraint = false;
5804                                 tginfo[j].tgdeferrable = false;
5805                                 tginfo[j].tginitdeferred = false;
5806                                 tginfo[j].tgconstrname = NULL;
5807                                 tginfo[j].tgconstrrelid = InvalidOid;
5808                                 tginfo[j].tgconstrrelname = NULL;
5809                         }
5810                         else
5811                         {
5812                                 tginfo[j].tgdef = NULL;
5813
5814                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5815                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5816                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5817                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5818                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5819                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5820                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5821
5822                                 if (tginfo[j].tgisconstraint)
5823                                 {
5824                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5825                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5826                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5827                                         {
5828                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5829                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5830                                                                                   tginfo[j].dobj.name,
5831                                                                                   tbinfo->dobj.name,
5832                                                                                   tginfo[j].tgconstrrelid);
5833                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5834                                         }
5835                                         else
5836                                                 tginfo[j].tgconstrrelname = NULL;
5837                                 }
5838                                 else
5839                                 {
5840                                         tginfo[j].tgconstrname = NULL;
5841                                         tginfo[j].tgconstrrelid = InvalidOid;
5842                                         tginfo[j].tgconstrrelname = NULL;
5843                                 }
5844                         }
5845                 }
5846
5847                 PQclear(res);
5848         }
5849
5850         destroyPQExpBuffer(query);
5851 }
5852
5853 /*
5854  * getEventTriggers
5855  *        get information about event triggers
5856  */
5857 EventTriggerInfo *
5858 getEventTriggers(Archive *fout, int *numEventTriggers)
5859 {
5860         int                     i;
5861         PQExpBuffer query;
5862         PGresult   *res;
5863         EventTriggerInfo *evtinfo;
5864         int                     i_tableoid,
5865                                 i_oid,
5866                                 i_evtname,
5867                                 i_evtevent,
5868                                 i_evtowner,
5869                                 i_evttags,
5870                                 i_evtfname,
5871                                 i_evtenabled;
5872         int                     ntups;
5873
5874         /* Before 9.3, there are no event triggers */
5875         if (fout->remoteVersion < 90300)
5876         {
5877                 *numEventTriggers = 0;
5878                 return NULL;
5879         }
5880
5881         query = createPQExpBuffer();
5882
5883         /* Make sure we are in proper schema */
5884         selectSourceSchema(fout, "pg_catalog");
5885
5886         appendPQExpBuffer(query,
5887                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5888                                           "evtevent, (%s evtowner) AS evtowner, "
5889                                           "array_to_string(array("
5890                                           "select quote_literal(x) "
5891                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5892                                           "e.evtfoid::regproc as evtfname "
5893                                           "FROM pg_event_trigger e "
5894                                           "ORDER BY e.oid",
5895                                           username_subquery);
5896
5897         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5898
5899         ntups = PQntuples(res);
5900
5901         *numEventTriggers = ntups;
5902
5903         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5904
5905         i_tableoid = PQfnumber(res, "tableoid");
5906         i_oid = PQfnumber(res, "oid");
5907         i_evtname = PQfnumber(res, "evtname");
5908         i_evtevent = PQfnumber(res, "evtevent");
5909         i_evtowner = PQfnumber(res, "evtowner");
5910         i_evttags = PQfnumber(res, "evttags");
5911         i_evtfname = PQfnumber(res, "evtfname");
5912         i_evtenabled = PQfnumber(res, "evtenabled");
5913
5914         for (i = 0; i < ntups; i++)
5915         {
5916                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5917                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5918                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5919                 AssignDumpId(&evtinfo[i].dobj);
5920                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5921                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5922                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5923                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5924                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5925                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5926                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5927         }
5928
5929         PQclear(res);
5930
5931         destroyPQExpBuffer(query);
5932
5933         return evtinfo;
5934 }
5935
5936 /*
5937  * getProcLangs
5938  *        get basic information about every procedural language in the system
5939  *
5940  * numProcLangs is set to the number of langs read in
5941  *
5942  * NB: this must run after getFuncs() because we assume we can do
5943  * findFuncByOid().
5944  */
5945 ProcLangInfo *
5946 getProcLangs(Archive *fout, int *numProcLangs)
5947 {
5948         PGresult   *res;
5949         int                     ntups;
5950         int                     i;
5951         PQExpBuffer query = createPQExpBuffer();
5952         ProcLangInfo *planginfo;
5953         int                     i_tableoid;
5954         int                     i_oid;
5955         int                     i_lanname;
5956         int                     i_lanpltrusted;
5957         int                     i_lanplcallfoid;
5958         int                     i_laninline;
5959         int                     i_lanvalidator;
5960         int                     i_lanacl;
5961         int                     i_lanowner;
5962
5963         /* Make sure we are in proper schema */
5964         selectSourceSchema(fout, "pg_catalog");
5965
5966         if (fout->remoteVersion >= 90000)
5967         {
5968                 /* pg_language has a laninline column */
5969                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5970                                                   "lanname, lanpltrusted, lanplcallfoid, "
5971                                                   "laninline, lanvalidator,  lanacl, "
5972                                                   "(%s lanowner) AS lanowner "
5973                                                   "FROM pg_language "
5974                                                   "WHERE lanispl "
5975                                                   "ORDER BY oid",
5976                                                   username_subquery);
5977         }
5978         else if (fout->remoteVersion >= 80300)
5979         {
5980                 /* pg_language has a lanowner column */
5981                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5982                                                   "lanname, lanpltrusted, lanplcallfoid, "
5983                                                   "lanvalidator,  lanacl, "
5984                                                   "(%s lanowner) AS lanowner "
5985                                                   "FROM pg_language "
5986                                                   "WHERE lanispl "
5987                                                   "ORDER BY oid",
5988                                                   username_subquery);
5989         }
5990         else if (fout->remoteVersion >= 80100)
5991         {
5992                 /* Languages are owned by the bootstrap superuser, OID 10 */
5993                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5994                                                   "(%s '10') AS lanowner "
5995                                                   "FROM pg_language "
5996                                                   "WHERE lanispl "
5997                                                   "ORDER BY oid",
5998                                                   username_subquery);
5999         }
6000         else if (fout->remoteVersion >= 70400)
6001         {
6002                 /* Languages are owned by the bootstrap superuser, sysid 1 */
6003                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6004                                                   "(%s '1') AS lanowner "
6005                                                   "FROM pg_language "
6006                                                   "WHERE lanispl "
6007                                                   "ORDER BY oid",
6008                                                   username_subquery);
6009         }
6010         else if (fout->remoteVersion >= 70100)
6011         {
6012                 /* No clear notion of an owner at all before 7.4 ... */
6013                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
6014                                                   "WHERE lanispl "
6015                                                   "ORDER BY oid");
6016         }
6017         else
6018         {
6019                 appendPQExpBuffer(query, "SELECT "
6020                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
6021                                                   "oid, * FROM pg_language "
6022                                                   "WHERE lanispl "
6023                                                   "ORDER BY oid");
6024         }
6025
6026         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6027
6028         ntups = PQntuples(res);
6029
6030         *numProcLangs = ntups;
6031
6032         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
6033
6034         i_tableoid = PQfnumber(res, "tableoid");
6035         i_oid = PQfnumber(res, "oid");
6036         i_lanname = PQfnumber(res, "lanname");
6037         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
6038         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
6039         /* these may fail and return -1: */
6040         i_laninline = PQfnumber(res, "laninline");
6041         i_lanvalidator = PQfnumber(res, "lanvalidator");
6042         i_lanacl = PQfnumber(res, "lanacl");
6043         i_lanowner = PQfnumber(res, "lanowner");
6044
6045         for (i = 0; i < ntups; i++)
6046         {
6047                 planginfo[i].dobj.objType = DO_PROCLANG;
6048                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6049                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6050                 AssignDumpId(&planginfo[i].dobj);
6051
6052                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
6053                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
6054                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
6055                 if (i_laninline >= 0)
6056                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
6057                 else
6058                         planginfo[i].laninline = InvalidOid;
6059                 if (i_lanvalidator >= 0)
6060                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
6061                 else
6062                         planginfo[i].lanvalidator = InvalidOid;
6063                 if (i_lanacl >= 0)
6064                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
6065                 else
6066                         planginfo[i].lanacl = pg_strdup("{=U}");
6067                 if (i_lanowner >= 0)
6068                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
6069                 else
6070                         planginfo[i].lanowner = pg_strdup("");
6071
6072                 if (fout->remoteVersion < 70300)
6073                 {
6074                         /*
6075                          * We need to make a dependency to ensure the function will be
6076                          * dumped first.  (In 7.3 and later the regular dependency
6077                          * mechanism will handle this for us.)
6078                          */
6079                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
6080
6081                         if (funcInfo)
6082                                 addObjectDependency(&planginfo[i].dobj,
6083                                                                         funcInfo->dobj.dumpId);
6084                 }
6085         }
6086
6087         PQclear(res);
6088
6089         destroyPQExpBuffer(query);
6090
6091         return planginfo;
6092 }
6093
6094 /*
6095  * getCasts
6096  *        get basic information about every cast in the system
6097  *
6098  * numCasts is set to the number of casts read in
6099  */
6100 CastInfo *
6101 getCasts(Archive *fout, int *numCasts)
6102 {
6103         PGresult   *res;
6104         int                     ntups;
6105         int                     i;
6106         PQExpBuffer query = createPQExpBuffer();
6107         CastInfo   *castinfo;
6108         int                     i_tableoid;
6109         int                     i_oid;
6110         int                     i_castsource;
6111         int                     i_casttarget;
6112         int                     i_castfunc;
6113         int                     i_castcontext;
6114         int                     i_castmethod;
6115
6116         /* Make sure we are in proper schema */
6117         selectSourceSchema(fout, "pg_catalog");
6118
6119         if (fout->remoteVersion >= 80400)
6120         {
6121                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6122                                                   "castsource, casttarget, castfunc, castcontext, "
6123                                                   "castmethod "
6124                                                   "FROM pg_cast ORDER BY 3,4");
6125         }
6126         else if (fout->remoteVersion >= 70300)
6127         {
6128                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6129                                                   "castsource, casttarget, castfunc, castcontext, "
6130                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6131                                                   "FROM pg_cast ORDER BY 3,4");
6132         }
6133         else
6134         {
6135                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
6136                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
6137                                                   "p.oid AS castfunc, 'e' AS castcontext, "
6138                                                   "'f' AS castmethod "
6139                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
6140                                                   "WHERE p.pronargs = 1 AND "
6141                                                   "p.proargtypes[0] = t1.oid AND "
6142                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
6143                                                   "ORDER BY 3,4");
6144         }
6145
6146         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6147
6148         ntups = PQntuples(res);
6149
6150         *numCasts = ntups;
6151
6152         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6153
6154         i_tableoid = PQfnumber(res, "tableoid");
6155         i_oid = PQfnumber(res, "oid");
6156         i_castsource = PQfnumber(res, "castsource");
6157         i_casttarget = PQfnumber(res, "casttarget");
6158         i_castfunc = PQfnumber(res, "castfunc");
6159         i_castcontext = PQfnumber(res, "castcontext");
6160         i_castmethod = PQfnumber(res, "castmethod");
6161
6162         for (i = 0; i < ntups; i++)
6163         {
6164                 PQExpBufferData namebuf;
6165                 TypeInfo   *sTypeInfo;
6166                 TypeInfo   *tTypeInfo;
6167
6168                 castinfo[i].dobj.objType = DO_CAST;
6169                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6170                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6171                 AssignDumpId(&castinfo[i].dobj);
6172                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6173                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6174                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6175                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6176                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6177
6178                 /*
6179                  * Try to name cast as concatenation of typnames.  This is only used
6180                  * for purposes of sorting.  If we fail to find either type, the name
6181                  * will be an empty string.
6182                  */
6183                 initPQExpBuffer(&namebuf);
6184                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6185                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6186                 if (sTypeInfo && tTypeInfo)
6187                         appendPQExpBuffer(&namebuf, "%s %s",
6188                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6189                 castinfo[i].dobj.name = namebuf.data;
6190
6191                 if (OidIsValid(castinfo[i].castfunc))
6192                 {
6193                         /*
6194                          * We need to make a dependency to ensure the function will be
6195                          * dumped first.  (In 7.3 and later the regular dependency
6196                          * mechanism will handle this for us.)
6197                          */
6198                         FuncInfo   *funcInfo;
6199
6200                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6201                         if (funcInfo)
6202                                 addObjectDependency(&castinfo[i].dobj,
6203                                                                         funcInfo->dobj.dumpId);
6204                 }
6205         }
6206
6207         PQclear(res);
6208
6209         destroyPQExpBuffer(query);
6210
6211         return castinfo;
6212 }
6213
6214 /*
6215  * getTableAttrs -
6216  *        for each interesting table, read info about its attributes
6217  *        (names, types, default values, CHECK constraints, etc)
6218  *
6219  * This is implemented in a very inefficient way right now, looping
6220  * through the tblinfo and doing a join per table to find the attrs and their
6221  * types.  However, because we want type names and so forth to be named
6222  * relative to the schema of each table, we couldn't do it in just one
6223  * query.  (Maybe one query per schema?)
6224  *
6225  *      modifies tblinfo
6226  */
6227 void
6228 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
6229 {
6230         int                     i,
6231                                 j;
6232         PQExpBuffer q = createPQExpBuffer();
6233         int                     i_attnum;
6234         int                     i_attname;
6235         int                     i_atttypname;
6236         int                     i_atttypmod;
6237         int                     i_attstattarget;
6238         int                     i_attstorage;
6239         int                     i_typstorage;
6240         int                     i_attnotnull;
6241         int                     i_atthasdef;
6242         int                     i_attisdropped;
6243         int                     i_attlen;
6244         int                     i_attalign;
6245         int                     i_attislocal;
6246         int                     i_attoptions;
6247         int                     i_attcollation;
6248         int                     i_attfdwoptions;
6249         PGresult   *res;
6250         int                     ntups;
6251         bool            hasdefaults;
6252
6253         for (i = 0; i < numTables; i++)
6254         {
6255                 TableInfo  *tbinfo = &tblinfo[i];
6256
6257                 /* Don't bother to collect info for sequences */
6258                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6259                         continue;
6260
6261                 /* Don't bother with uninteresting tables, either */
6262                 if (!tbinfo->interesting)
6263                         continue;
6264
6265                 /*
6266                  * Make sure we are in proper schema for this table; this allows
6267                  * correct retrieval of formatted type names and default exprs
6268                  */
6269                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6270
6271                 /* find all the user attributes and their types */
6272
6273                 /*
6274                  * we must read the attribute names in attribute number order! because
6275                  * we will use the attnum to index into the attnames array later.  We
6276                  * actually ask to order by "attrelid, attnum" because (at least up to
6277                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6278                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6279                  */
6280                 if (g_verbose)
6281                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
6282                                           tbinfo->dobj.name);
6283
6284                 resetPQExpBuffer(q);
6285
6286                 if (fout->remoteVersion >= 90200)
6287                 {
6288                         /*
6289                          * attfdwoptions is new in 9.2.
6290                          */
6291                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6292                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6293                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6294                                                           "a.attlen, a.attalign, a.attislocal, "
6295                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6296                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6297                                                           "CASE WHEN a.attcollation <> t.typcollation "
6298                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6299                                                           "pg_catalog.array_to_string(ARRAY("
6300                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6301                                                           "' ' || pg_catalog.quote_literal(option_value) "
6302                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6303                                                           "ORDER BY option_name"
6304                                                           "), E',\n    ') AS attfdwoptions "
6305                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6306                                                           "ON a.atttypid = t.oid "
6307                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6308                                                           "AND a.attnum > 0::pg_catalog.int2 "
6309                                                           "ORDER BY a.attrelid, a.attnum",
6310                                                           tbinfo->dobj.catId.oid);
6311                 }
6312                 else if (fout->remoteVersion >= 90100)
6313                 {
6314                         /*
6315                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6316                          * clauses for attributes whose collation is different from their
6317                          * type's default, we use a CASE here to suppress uninteresting
6318                          * attcollations cheaply.
6319                          */
6320                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6321                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6322                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6323                                                           "a.attlen, a.attalign, a.attislocal, "
6324                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6325                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6326                                                           "CASE WHEN a.attcollation <> t.typcollation "
6327                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6328                                                           "NULL AS attfdwoptions "
6329                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6330                                                           "ON a.atttypid = t.oid "
6331                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6332                                                           "AND a.attnum > 0::pg_catalog.int2 "
6333                                                           "ORDER BY a.attrelid, a.attnum",
6334                                                           tbinfo->dobj.catId.oid);
6335                 }
6336                 else if (fout->remoteVersion >= 90000)
6337                 {
6338                         /* attoptions is new in 9.0 */
6339                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6340                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6341                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6342                                                           "a.attlen, a.attalign, a.attislocal, "
6343                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6344                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6345                                                           "0 AS attcollation, "
6346                                                           "NULL AS attfdwoptions "
6347                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6348                                                           "ON a.atttypid = t.oid "
6349                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6350                                                           "AND a.attnum > 0::pg_catalog.int2 "
6351                                                           "ORDER BY a.attrelid, a.attnum",
6352                                                           tbinfo->dobj.catId.oid);
6353                 }
6354                 else if (fout->remoteVersion >= 70300)
6355                 {
6356                         /* need left join here to not fail on dropped columns ... */
6357                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6358                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6359                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6360                                                           "a.attlen, a.attalign, a.attislocal, "
6361                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6362                                                           "'' AS attoptions, 0 AS attcollation, "
6363                                                           "NULL AS attfdwoptions "
6364                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6365                                                           "ON a.atttypid = t.oid "
6366                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6367                                                           "AND a.attnum > 0::pg_catalog.int2 "
6368                                                           "ORDER BY a.attrelid, a.attnum",
6369                                                           tbinfo->dobj.catId.oid);
6370                 }
6371                 else if (fout->remoteVersion >= 70100)
6372                 {
6373                         /*
6374                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6375                          * we don't dump it because we can't tell whether it's been
6376                          * explicitly set or was just a default.
6377                          *
6378                          * attislocal doesn't exist before 7.3, either; in older databases
6379                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6380                          */
6381                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6382                                                           "-1 AS attstattarget, a.attstorage, "
6383                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6384                                                           "false AS attisdropped, a.attlen, "
6385                                                           "a.attalign, true AS attislocal, "
6386                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6387                                                           "'' AS attoptions, 0 AS attcollation, "
6388                                                           "NULL AS attfdwoptions "
6389                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6390                                                           "ON a.atttypid = t.oid "
6391                                                           "WHERE a.attrelid = '%u'::oid "
6392                                                           "AND a.attnum > 0::int2 "
6393                                                           "ORDER BY a.attrelid, a.attnum",
6394                                                           tbinfo->dobj.catId.oid);
6395                 }
6396                 else
6397                 {
6398                         /* format_type not available before 7.1 */
6399                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6400                                                           "-1 AS attstattarget, "
6401                                                           "attstorage, attstorage AS typstorage, "
6402                                                           "attnotnull, atthasdef, false AS attisdropped, "
6403                                                           "attlen, attalign, "
6404                                                           "true AS attislocal, "
6405                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6406                                                           "'' AS attoptions, 0 AS attcollation, "
6407                                                           "NULL AS attfdwoptions "
6408                                                           "FROM pg_attribute a "
6409                                                           "WHERE attrelid = '%u'::oid "
6410                                                           "AND attnum > 0::int2 "
6411                                                           "ORDER BY attrelid, attnum",
6412                                                           tbinfo->dobj.catId.oid);
6413                 }
6414
6415                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6416
6417                 ntups = PQntuples(res);
6418
6419                 i_attnum = PQfnumber(res, "attnum");
6420                 i_attname = PQfnumber(res, "attname");
6421                 i_atttypname = PQfnumber(res, "atttypname");
6422                 i_atttypmod = PQfnumber(res, "atttypmod");
6423                 i_attstattarget = PQfnumber(res, "attstattarget");
6424                 i_attstorage = PQfnumber(res, "attstorage");
6425                 i_typstorage = PQfnumber(res, "typstorage");
6426                 i_attnotnull = PQfnumber(res, "attnotnull");
6427                 i_atthasdef = PQfnumber(res, "atthasdef");
6428                 i_attisdropped = PQfnumber(res, "attisdropped");
6429                 i_attlen = PQfnumber(res, "attlen");
6430                 i_attalign = PQfnumber(res, "attalign");
6431                 i_attislocal = PQfnumber(res, "attislocal");
6432                 i_attoptions = PQfnumber(res, "attoptions");
6433                 i_attcollation = PQfnumber(res, "attcollation");
6434                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6435
6436                 tbinfo->numatts = ntups;
6437                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6438                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6439                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6440                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6441                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6442                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6443                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6444                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6445                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6446                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6447                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6448                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6449                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6450                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6451                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6452                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6453                 hasdefaults = false;
6454
6455                 for (j = 0; j < ntups; j++)
6456                 {
6457                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6458                                 exit_horribly(NULL,
6459                                                           "invalid column numbering in table \"%s\"\n",
6460                                                           tbinfo->dobj.name);
6461                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6462                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6463                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6464                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6465                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6466                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6467                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6468                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6469                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6470                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6471                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6472                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6473                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6474                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6475                         tbinfo->attrdefs[j] = NULL; /* fix below */
6476                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6477                                 hasdefaults = true;
6478                         /* these flags will be set in flagInhAttrs() */
6479                         tbinfo->inhNotNull[j] = false;
6480                 }
6481
6482                 PQclear(res);
6483
6484                 /*
6485                  * Get info about column defaults
6486                  */
6487                 if (hasdefaults)
6488                 {
6489                         AttrDefInfo *attrdefs;
6490                         int                     numDefaults;
6491
6492                         if (g_verbose)
6493                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
6494                                                   tbinfo->dobj.name);
6495
6496                         resetPQExpBuffer(q);
6497                         if (fout->remoteVersion >= 70300)
6498                         {
6499                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6500                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6501                                                                   "FROM pg_catalog.pg_attrdef "
6502                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6503                                                                   tbinfo->dobj.catId.oid);
6504                         }
6505                         else if (fout->remoteVersion >= 70200)
6506                         {
6507                                 /* 7.2 did not have OIDs in pg_attrdef */
6508                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6509                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6510                                                                   "FROM pg_attrdef "
6511                                                                   "WHERE adrelid = '%u'::oid",
6512                                                                   tbinfo->dobj.catId.oid);
6513                         }
6514                         else if (fout->remoteVersion >= 70100)
6515                         {
6516                                 /* no pg_get_expr, so must rely on adsrc */
6517                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6518                                                                   "FROM pg_attrdef "
6519                                                                   "WHERE adrelid = '%u'::oid",
6520                                                                   tbinfo->dobj.catId.oid);
6521                         }
6522                         else
6523                         {
6524                                 /* no pg_get_expr, no tableoid either */
6525                                 appendPQExpBuffer(q, "SELECT "
6526                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6527                                                                   "oid, adnum, adsrc "
6528                                                                   "FROM pg_attrdef "
6529                                                                   "WHERE adrelid = '%u'::oid",
6530                                                                   tbinfo->dobj.catId.oid);
6531                         }
6532                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6533
6534                         numDefaults = PQntuples(res);
6535                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6536
6537                         for (j = 0; j < numDefaults; j++)
6538                         {
6539                                 int                     adnum;
6540
6541                                 adnum = atoi(PQgetvalue(res, j, 2));
6542
6543                                 if (adnum <= 0 || adnum > ntups)
6544                                         exit_horribly(NULL,
6545                                                                   "invalid adnum value %d for table \"%s\"\n",
6546                                                                   adnum, tbinfo->dobj.name);
6547
6548                                 /*
6549                                  * dropped columns shouldn't have defaults, but just in case,
6550                                  * ignore 'em
6551                                  */
6552                                 if (tbinfo->attisdropped[adnum - 1])
6553                                         continue;
6554
6555                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6556                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6557                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6558                                 AssignDumpId(&attrdefs[j].dobj);
6559                                 attrdefs[j].adtable = tbinfo;
6560                                 attrdefs[j].adnum = adnum;
6561                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6562
6563                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6564                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6565
6566                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6567
6568                                 /*
6569                                  * Defaults on a VIEW must always be dumped as separate ALTER
6570                                  * TABLE commands.      Defaults on regular tables are dumped as
6571                                  * part of the CREATE TABLE if possible, which it won't be if
6572                                  * the column is not going to be emitted explicitly.
6573                                  */
6574                                 if (tbinfo->relkind == RELKIND_VIEW)
6575                                 {
6576                                         attrdefs[j].separate = true;
6577                                         /* needed in case pre-7.3 DB: */
6578                                         addObjectDependency(&attrdefs[j].dobj,
6579                                                                                 tbinfo->dobj.dumpId);
6580                                 }
6581                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6582                                 {
6583                                         /* column will be suppressed, print default separately */
6584                                         attrdefs[j].separate = true;
6585                                         /* needed in case pre-7.3 DB: */
6586                                         addObjectDependency(&attrdefs[j].dobj,
6587                                                                                 tbinfo->dobj.dumpId);
6588                                 }
6589                                 else
6590                                 {
6591                                         attrdefs[j].separate = false;
6592
6593                                         /*
6594                                          * Mark the default as needing to appear before the table,
6595                                          * so that any dependencies it has must be emitted before
6596                                          * the CREATE TABLE.  If this is not possible, we'll
6597                                          * change to "separate" mode while sorting dependencies.
6598                                          */
6599                                         addObjectDependency(&tbinfo->dobj,
6600                                                                                 attrdefs[j].dobj.dumpId);
6601                                 }
6602
6603                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6604                         }
6605                         PQclear(res);
6606                 }
6607
6608                 /*
6609                  * Get info about table CHECK constraints
6610                  */
6611                 if (tbinfo->ncheck > 0)
6612                 {
6613                         ConstraintInfo *constrs;
6614                         int                     numConstrs;
6615
6616                         if (g_verbose)
6617                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6618                                                   tbinfo->dobj.name);
6619
6620                         resetPQExpBuffer(q);
6621                         if (fout->remoteVersion >= 90200)
6622                         {
6623                                 /*
6624                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6625                                  * but it wasn't ever false for check constraints until 9.2).
6626                                  */
6627                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6628                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6629                                                                   "conislocal, convalidated "
6630                                                                   "FROM pg_catalog.pg_constraint "
6631                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6632                                                                   "   AND contype = 'c' "
6633                                                                   "ORDER BY conname",
6634                                                                   tbinfo->dobj.catId.oid);
6635                         }
6636                         else if (fout->remoteVersion >= 80400)
6637                         {
6638                                 /* conislocal is new in 8.4 */
6639                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6640                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6641                                                                   "conislocal, true AS convalidated "
6642                                                                   "FROM pg_catalog.pg_constraint "
6643                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6644                                                                   "   AND contype = 'c' "
6645                                                                   "ORDER BY conname",
6646                                                                   tbinfo->dobj.catId.oid);
6647                         }
6648                         else if (fout->remoteVersion >= 70400)
6649                         {
6650                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6651                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6652                                                                   "true AS conislocal, true AS convalidated "
6653                                                                   "FROM pg_catalog.pg_constraint "
6654                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6655                                                                   "   AND contype = 'c' "
6656                                                                   "ORDER BY conname",
6657                                                                   tbinfo->dobj.catId.oid);
6658                         }
6659                         else if (fout->remoteVersion >= 70300)
6660                         {
6661                                 /* no pg_get_constraintdef, must use consrc */
6662                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6663                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6664                                                                   "true AS conislocal, true AS convalidated "
6665                                                                   "FROM pg_catalog.pg_constraint "
6666                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6667                                                                   "   AND contype = 'c' "
6668                                                                   "ORDER BY conname",
6669                                                                   tbinfo->dobj.catId.oid);
6670                         }
6671                         else if (fout->remoteVersion >= 70200)
6672                         {
6673                                 /* 7.2 did not have OIDs in pg_relcheck */
6674                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6675                                                                   "rcname AS conname, "
6676                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6677                                                                   "true AS conislocal, true AS convalidated "
6678                                                                   "FROM pg_relcheck "
6679                                                                   "WHERE rcrelid = '%u'::oid "
6680                                                                   "ORDER BY rcname",
6681                                                                   tbinfo->dobj.catId.oid);
6682                         }
6683                         else if (fout->remoteVersion >= 70100)
6684                         {
6685                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6686                                                                   "rcname AS conname, "
6687                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6688                                                                   "true AS conislocal, true AS convalidated "
6689                                                                   "FROM pg_relcheck "
6690                                                                   "WHERE rcrelid = '%u'::oid "
6691                                                                   "ORDER BY rcname",
6692                                                                   tbinfo->dobj.catId.oid);
6693                         }
6694                         else
6695                         {
6696                                 /* no tableoid in 7.0 */
6697                                 appendPQExpBuffer(q, "SELECT "
6698                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6699                                                                   "oid, 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                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6708
6709                         numConstrs = PQntuples(res);
6710                         if (numConstrs != tbinfo->ncheck)
6711                         {
6712                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6713                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6714                                                                                  tbinfo->ncheck),
6715                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6716                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6717                                 exit_nicely(1);
6718                         }
6719
6720                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6721                         tbinfo->checkexprs = constrs;
6722
6723                         for (j = 0; j < numConstrs; j++)
6724                         {
6725                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6726
6727                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6728                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6729                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6730                                 AssignDumpId(&constrs[j].dobj);
6731                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6732                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6733                                 constrs[j].contable = tbinfo;
6734                                 constrs[j].condomain = NULL;
6735                                 constrs[j].contype = 'c';
6736                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6737                                 constrs[j].confrelid = InvalidOid;
6738                                 constrs[j].conindex = 0;
6739                                 constrs[j].condeferrable = false;
6740                                 constrs[j].condeferred = false;
6741                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6742
6743                                 /*
6744                                  * An unvalidated constraint needs to be dumped separately, so
6745                                  * that potentially-violating existing data is loaded before
6746                                  * the constraint.
6747                                  */
6748                                 constrs[j].separate = !validated;
6749
6750                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6751
6752                                 /*
6753                                  * Mark the constraint as needing to appear before the table
6754                                  * --- this is so that any other dependencies of the
6755                                  * constraint will be emitted before we try to create the
6756                                  * table.  If the constraint is to be dumped separately, it
6757                                  * will be dumped after data is loaded anyway, so don't do it.
6758                                  * (There's an automatic dependency in the opposite direction
6759                                  * anyway, so don't need to add one manually here.)
6760                                  */
6761                                 if (!constrs[j].separate)
6762                                         addObjectDependency(&tbinfo->dobj,
6763                                                                                 constrs[j].dobj.dumpId);
6764
6765                                 /*
6766                                  * If the constraint is inherited, this will be detected later
6767                                  * (in pre-8.4 databases).      We also detect later if the
6768                                  * constraint must be split out from the table definition.
6769                                  */
6770                         }
6771                         PQclear(res);
6772                 }
6773         }
6774
6775         destroyPQExpBuffer(q);
6776 }
6777
6778 /*
6779  * Test whether a column should be printed as part of table's CREATE TABLE.
6780  * Column number is zero-based.
6781  *
6782  * Normally this is always true, but it's false for dropped columns, as well
6783  * as those that were inherited without any local definition.  (If we print
6784  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6785  * However, in binary_upgrade mode, we must print all such columns anyway and
6786  * fix the attislocal/attisdropped state later, so as to keep control of the
6787  * physical column order.
6788  *
6789  * This function exists because there are scattered nonobvious places that
6790  * must be kept in sync with this decision.
6791  */
6792 bool
6793 shouldPrintColumn(TableInfo *tbinfo, int colno)
6794 {
6795         if (binary_upgrade)
6796                 return true;
6797         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6798 }
6799
6800
6801 /*
6802  * getTSParsers:
6803  *        read all text search parsers in the system catalogs and return them
6804  *        in the TSParserInfo* structure
6805  *
6806  *      numTSParsers is set to the number of parsers read in
6807  */
6808 TSParserInfo *
6809 getTSParsers(Archive *fout, int *numTSParsers)
6810 {
6811         PGresult   *res;
6812         int                     ntups;
6813         int                     i;
6814         PQExpBuffer query;
6815         TSParserInfo *prsinfo;
6816         int                     i_tableoid;
6817         int                     i_oid;
6818         int                     i_prsname;
6819         int                     i_prsnamespace;
6820         int                     i_prsstart;
6821         int                     i_prstoken;
6822         int                     i_prsend;
6823         int                     i_prsheadline;
6824         int                     i_prslextype;
6825
6826         /* Before 8.3, there is no built-in text search support */
6827         if (fout->remoteVersion < 80300)
6828         {
6829                 *numTSParsers = 0;
6830                 return NULL;
6831         }
6832
6833         query = createPQExpBuffer();
6834
6835         /*
6836          * find all text search objects, including builtin ones; we filter out
6837          * system-defined objects at dump-out time.
6838          */
6839
6840         /* Make sure we are in proper schema */
6841         selectSourceSchema(fout, "pg_catalog");
6842
6843         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6844                                           "prsstart::oid, prstoken::oid, "
6845                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6846                                           "FROM pg_ts_parser");
6847
6848         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6849
6850         ntups = PQntuples(res);
6851         *numTSParsers = ntups;
6852
6853         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6854
6855         i_tableoid = PQfnumber(res, "tableoid");
6856         i_oid = PQfnumber(res, "oid");
6857         i_prsname = PQfnumber(res, "prsname");
6858         i_prsnamespace = PQfnumber(res, "prsnamespace");
6859         i_prsstart = PQfnumber(res, "prsstart");
6860         i_prstoken = PQfnumber(res, "prstoken");
6861         i_prsend = PQfnumber(res, "prsend");
6862         i_prsheadline = PQfnumber(res, "prsheadline");
6863         i_prslextype = PQfnumber(res, "prslextype");
6864
6865         for (i = 0; i < ntups; i++)
6866         {
6867                 prsinfo[i].dobj.objType = DO_TSPARSER;
6868                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6869                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6870                 AssignDumpId(&prsinfo[i].dobj);
6871                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6872                 prsinfo[i].dobj.namespace =
6873                         findNamespace(fout,
6874                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6875                                                   prsinfo[i].dobj.catId.oid);
6876                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6877                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6878                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6879                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6880                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6881
6882                 /* Decide whether we want to dump it */
6883                 selectDumpableObject(&(prsinfo[i].dobj));
6884         }
6885
6886         PQclear(res);
6887
6888         destroyPQExpBuffer(query);
6889
6890         return prsinfo;
6891 }
6892
6893 /*
6894  * getTSDictionaries:
6895  *        read all text search dictionaries in the system catalogs and return them
6896  *        in the TSDictInfo* structure
6897  *
6898  *      numTSDicts is set to the number of dictionaries read in
6899  */
6900 TSDictInfo *
6901 getTSDictionaries(Archive *fout, int *numTSDicts)
6902 {
6903         PGresult   *res;
6904         int                     ntups;
6905         int                     i;
6906         PQExpBuffer query;
6907         TSDictInfo *dictinfo;
6908         int                     i_tableoid;
6909         int                     i_oid;
6910         int                     i_dictname;
6911         int                     i_dictnamespace;
6912         int                     i_rolname;
6913         int                     i_dicttemplate;
6914         int                     i_dictinitoption;
6915
6916         /* Before 8.3, there is no built-in text search support */
6917         if (fout->remoteVersion < 80300)
6918         {
6919                 *numTSDicts = 0;
6920                 return NULL;
6921         }
6922
6923         query = createPQExpBuffer();
6924
6925         /* Make sure we are in proper schema */
6926         selectSourceSchema(fout, "pg_catalog");
6927
6928         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6929                                           "dictnamespace, (%s dictowner) AS rolname, "
6930                                           "dicttemplate, dictinitoption "
6931                                           "FROM pg_ts_dict",
6932                                           username_subquery);
6933
6934         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6935
6936         ntups = PQntuples(res);
6937         *numTSDicts = ntups;
6938
6939         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6940
6941         i_tableoid = PQfnumber(res, "tableoid");
6942         i_oid = PQfnumber(res, "oid");
6943         i_dictname = PQfnumber(res, "dictname");
6944         i_dictnamespace = PQfnumber(res, "dictnamespace");
6945         i_rolname = PQfnumber(res, "rolname");
6946         i_dictinitoption = PQfnumber(res, "dictinitoption");
6947         i_dicttemplate = PQfnumber(res, "dicttemplate");
6948
6949         for (i = 0; i < ntups; i++)
6950         {
6951                 dictinfo[i].dobj.objType = DO_TSDICT;
6952                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6953                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6954                 AssignDumpId(&dictinfo[i].dobj);
6955                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6956                 dictinfo[i].dobj.namespace =
6957                         findNamespace(fout,
6958                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6959                                                   dictinfo[i].dobj.catId.oid);
6960                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6961                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6962                 if (PQgetisnull(res, i, i_dictinitoption))
6963                         dictinfo[i].dictinitoption = NULL;
6964                 else
6965                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6966
6967                 /* Decide whether we want to dump it */
6968                 selectDumpableObject(&(dictinfo[i].dobj));
6969         }
6970
6971         PQclear(res);
6972
6973         destroyPQExpBuffer(query);
6974
6975         return dictinfo;
6976 }
6977
6978 /*
6979  * getTSTemplates:
6980  *        read all text search templates in the system catalogs and return them
6981  *        in the TSTemplateInfo* structure
6982  *
6983  *      numTSTemplates is set to the number of templates read in
6984  */
6985 TSTemplateInfo *
6986 getTSTemplates(Archive *fout, int *numTSTemplates)
6987 {
6988         PGresult   *res;
6989         int                     ntups;
6990         int                     i;
6991         PQExpBuffer query;
6992         TSTemplateInfo *tmplinfo;
6993         int                     i_tableoid;
6994         int                     i_oid;
6995         int                     i_tmplname;
6996         int                     i_tmplnamespace;
6997         int                     i_tmplinit;
6998         int                     i_tmpllexize;
6999
7000         /* Before 8.3, there is no built-in text search support */
7001         if (fout->remoteVersion < 80300)
7002         {
7003                 *numTSTemplates = 0;
7004                 return NULL;
7005         }
7006
7007         query = createPQExpBuffer();
7008
7009         /* Make sure we are in proper schema */
7010         selectSourceSchema(fout, "pg_catalog");
7011
7012         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
7013                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
7014                                           "FROM pg_ts_template");
7015
7016         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7017
7018         ntups = PQntuples(res);
7019         *numTSTemplates = ntups;
7020
7021         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
7022
7023         i_tableoid = PQfnumber(res, "tableoid");
7024         i_oid = PQfnumber(res, "oid");
7025         i_tmplname = PQfnumber(res, "tmplname");
7026         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
7027         i_tmplinit = PQfnumber(res, "tmplinit");
7028         i_tmpllexize = PQfnumber(res, "tmpllexize");
7029
7030         for (i = 0; i < ntups; i++)
7031         {
7032                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
7033                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7034                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7035                 AssignDumpId(&tmplinfo[i].dobj);
7036                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
7037                 tmplinfo[i].dobj.namespace =
7038                         findNamespace(fout,
7039                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
7040                                                   tmplinfo[i].dobj.catId.oid);
7041                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
7042                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
7043
7044                 /* Decide whether we want to dump it */
7045                 selectDumpableObject(&(tmplinfo[i].dobj));
7046         }
7047
7048         PQclear(res);
7049
7050         destroyPQExpBuffer(query);
7051
7052         return tmplinfo;
7053 }
7054
7055 /*
7056  * getTSConfigurations:
7057  *        read all text search configurations in the system catalogs and return
7058  *        them in the TSConfigInfo* structure
7059  *
7060  *      numTSConfigs is set to the number of configurations read in
7061  */
7062 TSConfigInfo *
7063 getTSConfigurations(Archive *fout, int *numTSConfigs)
7064 {
7065         PGresult   *res;
7066         int                     ntups;
7067         int                     i;
7068         PQExpBuffer query;
7069         TSConfigInfo *cfginfo;
7070         int                     i_tableoid;
7071         int                     i_oid;
7072         int                     i_cfgname;
7073         int                     i_cfgnamespace;
7074         int                     i_rolname;
7075         int                     i_cfgparser;
7076
7077         /* Before 8.3, there is no built-in text search support */
7078         if (fout->remoteVersion < 80300)
7079         {
7080                 *numTSConfigs = 0;
7081                 return NULL;
7082         }
7083
7084         query = createPQExpBuffer();
7085
7086         /* Make sure we are in proper schema */
7087         selectSourceSchema(fout, "pg_catalog");
7088
7089         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
7090                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
7091                                           "FROM pg_ts_config",
7092                                           username_subquery);
7093
7094         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7095
7096         ntups = PQntuples(res);
7097         *numTSConfigs = ntups;
7098
7099         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
7100
7101         i_tableoid = PQfnumber(res, "tableoid");
7102         i_oid = PQfnumber(res, "oid");
7103         i_cfgname = PQfnumber(res, "cfgname");
7104         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
7105         i_rolname = PQfnumber(res, "rolname");
7106         i_cfgparser = PQfnumber(res, "cfgparser");
7107
7108         for (i = 0; i < ntups; i++)
7109         {
7110                 cfginfo[i].dobj.objType = DO_TSCONFIG;
7111                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7112                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7113                 AssignDumpId(&cfginfo[i].dobj);
7114                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
7115                 cfginfo[i].dobj.namespace =
7116                         findNamespace(fout,
7117                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
7118                                                   cfginfo[i].dobj.catId.oid);
7119                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7120                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7121
7122                 /* Decide whether we want to dump it */
7123                 selectDumpableObject(&(cfginfo[i].dobj));
7124         }
7125
7126         PQclear(res);
7127
7128         destroyPQExpBuffer(query);
7129
7130         return cfginfo;
7131 }
7132
7133 /*
7134  * getForeignDataWrappers:
7135  *        read all foreign-data wrappers in the system catalogs and return
7136  *        them in the FdwInfo* structure
7137  *
7138  *      numForeignDataWrappers is set to the number of fdws read in
7139  */
7140 FdwInfo *
7141 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7142 {
7143         PGresult   *res;
7144         int                     ntups;
7145         int                     i;
7146         PQExpBuffer query = createPQExpBuffer();
7147         FdwInfo    *fdwinfo;
7148         int                     i_tableoid;
7149         int                     i_oid;
7150         int                     i_fdwname;
7151         int                     i_rolname;
7152         int                     i_fdwhandler;
7153         int                     i_fdwvalidator;
7154         int                     i_fdwacl;
7155         int                     i_fdwoptions;
7156
7157         /* Before 8.4, there are no foreign-data wrappers */
7158         if (fout->remoteVersion < 80400)
7159         {
7160                 *numForeignDataWrappers = 0;
7161                 return NULL;
7162         }
7163
7164         /* Make sure we are in proper schema */
7165         selectSourceSchema(fout, "pg_catalog");
7166
7167         if (fout->remoteVersion >= 90100)
7168         {
7169                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7170                                                   "(%s fdwowner) AS rolname, "
7171                                                   "fdwhandler::pg_catalog.regproc, "
7172                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7173                                                   "array_to_string(ARRAY("
7174                                                   "SELECT quote_ident(option_name) || ' ' || "
7175                                                   "quote_literal(option_value) "
7176                                                   "FROM pg_options_to_table(fdwoptions) "
7177                                                   "ORDER BY option_name"
7178                                                   "), E',\n    ') AS fdwoptions "
7179                                                   "FROM pg_foreign_data_wrapper",
7180                                                   username_subquery);
7181         }
7182         else
7183         {
7184                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7185                                                   "(%s fdwowner) AS rolname, "
7186                                                   "'-' AS fdwhandler, "
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
7198         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7199
7200         ntups = PQntuples(res);
7201         *numForeignDataWrappers = ntups;
7202
7203         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7204
7205         i_tableoid = PQfnumber(res, "tableoid");
7206         i_oid = PQfnumber(res, "oid");
7207         i_fdwname = PQfnumber(res, "fdwname");
7208         i_rolname = PQfnumber(res, "rolname");
7209         i_fdwhandler = PQfnumber(res, "fdwhandler");
7210         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7211         i_fdwacl = PQfnumber(res, "fdwacl");
7212         i_fdwoptions = PQfnumber(res, "fdwoptions");
7213
7214         for (i = 0; i < ntups; i++)
7215         {
7216                 fdwinfo[i].dobj.objType = DO_FDW;
7217                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7218                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7219                 AssignDumpId(&fdwinfo[i].dobj);
7220                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7221                 fdwinfo[i].dobj.namespace = NULL;
7222                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7223                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7224                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7225                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7226                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7227
7228                 /* Decide whether we want to dump it */
7229                 selectDumpableObject(&(fdwinfo[i].dobj));
7230         }
7231
7232         PQclear(res);
7233
7234         destroyPQExpBuffer(query);
7235
7236         return fdwinfo;
7237 }
7238
7239 /*
7240  * getForeignServers:
7241  *        read all foreign servers in the system catalogs and return
7242  *        them in the ForeignServerInfo * structure
7243  *
7244  *      numForeignServers is set to the number of servers read in
7245  */
7246 ForeignServerInfo *
7247 getForeignServers(Archive *fout, int *numForeignServers)
7248 {
7249         PGresult   *res;
7250         int                     ntups;
7251         int                     i;
7252         PQExpBuffer query = createPQExpBuffer();
7253         ForeignServerInfo *srvinfo;
7254         int                     i_tableoid;
7255         int                     i_oid;
7256         int                     i_srvname;
7257         int                     i_rolname;
7258         int                     i_srvfdw;
7259         int                     i_srvtype;
7260         int                     i_srvversion;
7261         int                     i_srvacl;
7262         int                     i_srvoptions;
7263
7264         /* Before 8.4, there are no foreign servers */
7265         if (fout->remoteVersion < 80400)
7266         {
7267                 *numForeignServers = 0;
7268                 return NULL;
7269         }
7270
7271         /* Make sure we are in proper schema */
7272         selectSourceSchema(fout, "pg_catalog");
7273
7274         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7275                                           "(%s srvowner) AS rolname, "
7276                                           "srvfdw, srvtype, srvversion, srvacl,"
7277                                           "array_to_string(ARRAY("
7278                                           "SELECT quote_ident(option_name) || ' ' || "
7279                                           "quote_literal(option_value) "
7280                                           "FROM pg_options_to_table(srvoptions) "
7281                                           "ORDER BY option_name"
7282                                           "), E',\n    ') AS srvoptions "
7283                                           "FROM pg_foreign_server",
7284                                           username_subquery);
7285
7286         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7287
7288         ntups = PQntuples(res);
7289         *numForeignServers = ntups;
7290
7291         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7292
7293         i_tableoid = PQfnumber(res, "tableoid");
7294         i_oid = PQfnumber(res, "oid");
7295         i_srvname = PQfnumber(res, "srvname");
7296         i_rolname = PQfnumber(res, "rolname");
7297         i_srvfdw = PQfnumber(res, "srvfdw");
7298         i_srvtype = PQfnumber(res, "srvtype");
7299         i_srvversion = PQfnumber(res, "srvversion");
7300         i_srvacl = PQfnumber(res, "srvacl");
7301         i_srvoptions = PQfnumber(res, "srvoptions");
7302
7303         for (i = 0; i < ntups; i++)
7304         {
7305                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7306                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7307                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7308                 AssignDumpId(&srvinfo[i].dobj);
7309                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7310                 srvinfo[i].dobj.namespace = NULL;
7311                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7312                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7313                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7314                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7315                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7316                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7317
7318                 /* Decide whether we want to dump it */
7319                 selectDumpableObject(&(srvinfo[i].dobj));
7320         }
7321
7322         PQclear(res);
7323
7324         destroyPQExpBuffer(query);
7325
7326         return srvinfo;
7327 }
7328
7329 /*
7330  * getDefaultACLs:
7331  *        read all default ACL information in the system catalogs and return
7332  *        them in the DefaultACLInfo structure
7333  *
7334  *      numDefaultACLs is set to the number of ACLs read in
7335  */
7336 DefaultACLInfo *
7337 getDefaultACLs(Archive *fout, int *numDefaultACLs)
7338 {
7339         DefaultACLInfo *daclinfo;
7340         PQExpBuffer query;
7341         PGresult   *res;
7342         int                     i_oid;
7343         int                     i_tableoid;
7344         int                     i_defaclrole;
7345         int                     i_defaclnamespace;
7346         int                     i_defaclobjtype;
7347         int                     i_defaclacl;
7348         int                     i,
7349                                 ntups;
7350
7351         if (fout->remoteVersion < 90000)
7352         {
7353                 *numDefaultACLs = 0;
7354                 return NULL;
7355         }
7356
7357         query = createPQExpBuffer();
7358
7359         /* Make sure we are in proper schema */
7360         selectSourceSchema(fout, "pg_catalog");
7361
7362         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7363                                           "(%s defaclrole) AS defaclrole, "
7364                                           "defaclnamespace, "
7365                                           "defaclobjtype, "
7366                                           "defaclacl "
7367                                           "FROM pg_default_acl",
7368                                           username_subquery);
7369
7370         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7371
7372         ntups = PQntuples(res);
7373         *numDefaultACLs = ntups;
7374
7375         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7376
7377         i_oid = PQfnumber(res, "oid");
7378         i_tableoid = PQfnumber(res, "tableoid");
7379         i_defaclrole = PQfnumber(res, "defaclrole");
7380         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7381         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7382         i_defaclacl = PQfnumber(res, "defaclacl");
7383
7384         for (i = 0; i < ntups; i++)
7385         {
7386                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7387
7388                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7389                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7390                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7391                 AssignDumpId(&daclinfo[i].dobj);
7392                 /* cheesy ... is it worth coming up with a better object name? */
7393                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7394
7395                 if (nspid != InvalidOid)
7396                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7397                                                                                                  daclinfo[i].dobj.catId.oid);
7398                 else
7399                         daclinfo[i].dobj.namespace = NULL;
7400
7401                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7402                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7403                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7404
7405                 /* Decide whether we want to dump it */
7406                 selectDumpableDefaultACL(&(daclinfo[i]));
7407         }
7408
7409         PQclear(res);
7410
7411         destroyPQExpBuffer(query);
7412
7413         return daclinfo;
7414 }
7415
7416 /*
7417  * dumpComment --
7418  *
7419  * This routine is used to dump any comments associated with the
7420  * object handed to this routine. The routine takes a constant character
7421  * string for the target part of the comment-creation command, plus
7422  * the namespace and owner of the object (for labeling the ArchiveEntry),
7423  * plus catalog ID and subid which are the lookup key for pg_description,
7424  * plus the dump ID for the object (for setting a dependency).
7425  * If a matching pg_description entry is found, it is dumped.
7426  *
7427  * Note: although this routine takes a dumpId for dependency purposes,
7428  * that purpose is just to mark the dependency in the emitted dump file
7429  * for possible future use by pg_restore.  We do NOT use it for determining
7430  * ordering of the comment in the dump file, because this routine is called
7431  * after dependency sorting occurs.  This routine should be called just after
7432  * calling ArchiveEntry() for the specified object.
7433  */
7434 static void
7435 dumpComment(Archive *fout, const char *target,
7436                         const char *namespace, const char *owner,
7437                         CatalogId catalogId, int subid, DumpId dumpId)
7438 {
7439         CommentItem *comments;
7440         int                     ncomments;
7441
7442         /* Comments are schema not data ... except blob comments are data */
7443         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7444         {
7445                 if (dataOnly)
7446                         return;
7447         }
7448         else
7449         {
7450                 if (schemaOnly)
7451                         return;
7452         }
7453
7454         /* Search for comments associated with catalogId, using table */
7455         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7456                                                          &comments);
7457
7458         /* Is there one matching the subid? */
7459         while (ncomments > 0)
7460         {
7461                 if (comments->objsubid == subid)
7462                         break;
7463                 comments++;
7464                 ncomments--;
7465         }
7466
7467         /* If a comment exists, build COMMENT ON statement */
7468         if (ncomments > 0)
7469         {
7470                 PQExpBuffer query = createPQExpBuffer();
7471
7472                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7473                 appendStringLiteralAH(query, comments->descr, fout);
7474                 appendPQExpBuffer(query, ";\n");
7475
7476                 /*
7477                  * We mark comments as SECTION_NONE because they really belong in the
7478                  * same section as their parent, whether that is pre-data or
7479                  * post-data.
7480                  */
7481                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7482                                          target, namespace, NULL, owner,
7483                                          false, "COMMENT", SECTION_NONE,
7484                                          query->data, "", NULL,
7485                                          &(dumpId), 1,
7486                                          NULL, NULL);
7487
7488                 destroyPQExpBuffer(query);
7489         }
7490 }
7491
7492 /*
7493  * dumpTableComment --
7494  *
7495  * As above, but dump comments for both the specified table (or view)
7496  * and its columns.
7497  */
7498 static void
7499 dumpTableComment(Archive *fout, TableInfo *tbinfo,
7500                                  const char *reltypename)
7501 {
7502         CommentItem *comments;
7503         int                     ncomments;
7504         PQExpBuffer query;
7505         PQExpBuffer target;
7506
7507         /* Comments are SCHEMA not data */
7508         if (dataOnly)
7509                 return;
7510
7511         /* Search for comments associated with relation, using table */
7512         ncomments = findComments(fout,
7513                                                          tbinfo->dobj.catId.tableoid,
7514                                                          tbinfo->dobj.catId.oid,
7515                                                          &comments);
7516
7517         /* If comments exist, build COMMENT ON statements */
7518         if (ncomments <= 0)
7519                 return;
7520
7521         query = createPQExpBuffer();
7522         target = createPQExpBuffer();
7523
7524         while (ncomments > 0)
7525         {
7526                 const char *descr = comments->descr;
7527                 int                     objsubid = comments->objsubid;
7528
7529                 if (objsubid == 0)
7530                 {
7531                         resetPQExpBuffer(target);
7532                         appendPQExpBuffer(target, "%s %s", reltypename,
7533                                                           fmtId(tbinfo->dobj.name));
7534
7535                         resetPQExpBuffer(query);
7536                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7537                         appendStringLiteralAH(query, descr, fout);
7538                         appendPQExpBuffer(query, ";\n");
7539
7540                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7541                                                  target->data,
7542                                                  tbinfo->dobj.namespace->dobj.name,
7543                                                  NULL, tbinfo->rolname,
7544                                                  false, "COMMENT", SECTION_NONE,
7545                                                  query->data, "", NULL,
7546                                                  &(tbinfo->dobj.dumpId), 1,
7547                                                  NULL, NULL);
7548                 }
7549                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7550                 {
7551                         resetPQExpBuffer(target);
7552                         appendPQExpBuffer(target, "COLUMN %s.",
7553                                                           fmtId(tbinfo->dobj.name));
7554                         appendPQExpBuffer(target, "%s",
7555                                                           fmtId(tbinfo->attnames[objsubid - 1]));
7556
7557                         resetPQExpBuffer(query);
7558                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7559                         appendStringLiteralAH(query, descr, fout);
7560                         appendPQExpBuffer(query, ";\n");
7561
7562                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7563                                                  target->data,
7564                                                  tbinfo->dobj.namespace->dobj.name,
7565                                                  NULL, tbinfo->rolname,
7566                                                  false, "COMMENT", SECTION_NONE,
7567                                                  query->data, "", NULL,
7568                                                  &(tbinfo->dobj.dumpId), 1,
7569                                                  NULL, NULL);
7570                 }
7571
7572                 comments++;
7573                 ncomments--;
7574         }
7575
7576         destroyPQExpBuffer(query);
7577         destroyPQExpBuffer(target);
7578 }
7579
7580 /*
7581  * findComments --
7582  *
7583  * Find the comment(s), if any, associated with the given object.  All the
7584  * objsubid values associated with the given classoid/objoid are found with
7585  * one search.
7586  */
7587 static int
7588 findComments(Archive *fout, Oid classoid, Oid objoid,
7589                          CommentItem **items)
7590 {
7591         /* static storage for table of comments */
7592         static CommentItem *comments = NULL;
7593         static int      ncomments = -1;
7594
7595         CommentItem *middle = NULL;
7596         CommentItem *low;
7597         CommentItem *high;
7598         int                     nmatch;
7599
7600         /* Get comments if we didn't already */
7601         if (ncomments < 0)
7602                 ncomments = collectComments(fout, &comments);
7603
7604         /*
7605          * Pre-7.2, pg_description does not contain classoid, so collectComments
7606          * just stores a zero.  If there's a collision on object OID, well, you
7607          * get duplicate comments.
7608          */
7609         if (fout->remoteVersion < 70200)
7610                 classoid = 0;
7611
7612         /*
7613          * Do binary search to find some item matching the object.
7614          */
7615         low = &comments[0];
7616         high = &comments[ncomments - 1];
7617         while (low <= high)
7618         {
7619                 middle = low + (high - low) / 2;
7620
7621                 if (classoid < middle->classoid)
7622                         high = middle - 1;
7623                 else if (classoid > middle->classoid)
7624                         low = middle + 1;
7625                 else if (objoid < middle->objoid)
7626                         high = middle - 1;
7627                 else if (objoid > middle->objoid)
7628                         low = middle + 1;
7629                 else
7630                         break;                          /* found a match */
7631         }
7632
7633         if (low > high)                         /* no matches */
7634         {
7635                 *items = NULL;
7636                 return 0;
7637         }
7638
7639         /*
7640          * Now determine how many items match the object.  The search loop
7641          * invariant still holds: only items between low and high inclusive could
7642          * match.
7643          */
7644         nmatch = 1;
7645         while (middle > low)
7646         {
7647                 if (classoid != middle[-1].classoid ||
7648                         objoid != middle[-1].objoid)
7649                         break;
7650                 middle--;
7651                 nmatch++;
7652         }
7653
7654         *items = middle;
7655
7656         middle += nmatch;
7657         while (middle <= high)
7658         {
7659                 if (classoid != middle->classoid ||
7660                         objoid != middle->objoid)
7661                         break;
7662                 middle++;
7663                 nmatch++;
7664         }
7665
7666         return nmatch;
7667 }
7668
7669 /*
7670  * collectComments --
7671  *
7672  * Construct a table of all comments available for database objects.
7673  * We used to do per-object queries for the comments, but it's much faster
7674  * to pull them all over at once, and on most databases the memory cost
7675  * isn't high.
7676  *
7677  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7678  */
7679 static int
7680 collectComments(Archive *fout, CommentItem **items)
7681 {
7682         PGresult   *res;
7683         PQExpBuffer query;
7684         int                     i_description;
7685         int                     i_classoid;
7686         int                     i_objoid;
7687         int                     i_objsubid;
7688         int                     ntups;
7689         int                     i;
7690         CommentItem *comments;
7691
7692         /*
7693          * Note we do NOT change source schema here; preserve the caller's
7694          * setting, instead.
7695          */
7696
7697         query = createPQExpBuffer();
7698
7699         if (fout->remoteVersion >= 70300)
7700         {
7701                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7702                                                   "FROM pg_catalog.pg_description "
7703                                                   "ORDER BY classoid, objoid, objsubid");
7704         }
7705         else if (fout->remoteVersion >= 70200)
7706         {
7707                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7708                                                   "FROM pg_description "
7709                                                   "ORDER BY classoid, objoid, objsubid");
7710         }
7711         else
7712         {
7713                 /* Note: this will fail to find attribute comments in pre-7.2... */
7714                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7715                                                   "FROM pg_description "
7716                                                   "ORDER BY objoid");
7717         }
7718
7719         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7720
7721         /* Construct lookup table containing OIDs in numeric form */
7722
7723         i_description = PQfnumber(res, "description");
7724         i_classoid = PQfnumber(res, "classoid");
7725         i_objoid = PQfnumber(res, "objoid");
7726         i_objsubid = PQfnumber(res, "objsubid");
7727
7728         ntups = PQntuples(res);
7729
7730         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7731
7732         for (i = 0; i < ntups; i++)
7733         {
7734                 comments[i].descr = PQgetvalue(res, i, i_description);
7735                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7736                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7737                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7738         }
7739
7740         /* Do NOT free the PGresult since we are keeping pointers into it */
7741         destroyPQExpBuffer(query);
7742
7743         *items = comments;
7744         return ntups;
7745 }
7746
7747 /*
7748  * dumpDumpableObject
7749  *
7750  * This routine and its subsidiaries are responsible for creating
7751  * ArchiveEntries (TOC objects) for each object to be dumped.
7752  */
7753 static void
7754 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7755 {
7756         switch (dobj->objType)
7757         {
7758                 case DO_NAMESPACE:
7759                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7760                         break;
7761                 case DO_EXTENSION:
7762                         dumpExtension(fout, (ExtensionInfo *) dobj);
7763                         break;
7764                 case DO_TYPE:
7765                         dumpType(fout, (TypeInfo *) dobj);
7766                         break;
7767                 case DO_SHELL_TYPE:
7768                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7769                         break;
7770                 case DO_FUNC:
7771                         dumpFunc(fout, (FuncInfo *) dobj);
7772                         break;
7773                 case DO_AGG:
7774                         dumpAgg(fout, (AggInfo *) dobj);
7775                         break;
7776                 case DO_OPERATOR:
7777                         dumpOpr(fout, (OprInfo *) dobj);
7778                         break;
7779                 case DO_OPCLASS:
7780                         dumpOpclass(fout, (OpclassInfo *) dobj);
7781                         break;
7782                 case DO_OPFAMILY:
7783                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7784                         break;
7785                 case DO_COLLATION:
7786                         dumpCollation(fout, (CollInfo *) dobj);
7787                         break;
7788                 case DO_CONVERSION:
7789                         dumpConversion(fout, (ConvInfo *) dobj);
7790                         break;
7791                 case DO_TABLE:
7792                         dumpTable(fout, (TableInfo *) dobj);
7793                         break;
7794                 case DO_ATTRDEF:
7795                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7796                         break;
7797                 case DO_INDEX:
7798                         dumpIndex(fout, (IndxInfo *) dobj);
7799                         break;
7800                 case DO_REFRESH_MATVIEW:
7801                         refreshMatViewData(fout, (TableDataInfo *) dobj);
7802                         break;
7803                 case DO_RULE:
7804                         dumpRule(fout, (RuleInfo *) dobj);
7805                         break;
7806                 case DO_TRIGGER:
7807                         dumpTrigger(fout, (TriggerInfo *) dobj);
7808                         break;
7809                 case DO_EVENT_TRIGGER:
7810                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7811                         break;
7812                 case DO_CONSTRAINT:
7813                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7814                         break;
7815                 case DO_FK_CONSTRAINT:
7816                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7817                         break;
7818                 case DO_PROCLANG:
7819                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7820                         break;
7821                 case DO_CAST:
7822                         dumpCast(fout, (CastInfo *) dobj);
7823                         break;
7824                 case DO_TABLE_DATA:
7825                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
7826                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
7827                         else
7828                                 dumpTableData(fout, (TableDataInfo *) dobj);
7829                         break;
7830                 case DO_DUMMY_TYPE:
7831                         /* table rowtypes and array types are never dumped separately */
7832                         break;
7833                 case DO_TSPARSER:
7834                         dumpTSParser(fout, (TSParserInfo *) dobj);
7835                         break;
7836                 case DO_TSDICT:
7837                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7838                         break;
7839                 case DO_TSTEMPLATE:
7840                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7841                         break;
7842                 case DO_TSCONFIG:
7843                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7844                         break;
7845                 case DO_FDW:
7846                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7847                         break;
7848                 case DO_FOREIGN_SERVER:
7849                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7850                         break;
7851                 case DO_DEFAULT_ACL:
7852                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7853                         break;
7854                 case DO_BLOB:
7855                         dumpBlob(fout, (BlobInfo *) dobj);
7856                         break;
7857                 case DO_BLOB_DATA:
7858                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7859                                                  dobj->name, NULL, NULL, "",
7860                                                  false, "BLOBS", SECTION_DATA,
7861                                                  "", "", NULL,
7862                                                  NULL, 0,
7863                                                  dumpBlobs, NULL);
7864                         break;
7865                 case DO_PRE_DATA_BOUNDARY:
7866                 case DO_POST_DATA_BOUNDARY:
7867                         /* never dumped, nothing to do */
7868                         break;
7869         }
7870 }
7871
7872 /*
7873  * dumpNamespace
7874  *        writes out to fout the queries to recreate a user-defined namespace
7875  */
7876 static void
7877 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7878 {
7879         PQExpBuffer q;
7880         PQExpBuffer delq;
7881         PQExpBuffer labelq;
7882         char       *qnspname;
7883
7884         /* Skip if not to be dumped */
7885         if (!nspinfo->dobj.dump || dataOnly)
7886                 return;
7887
7888         /* don't dump dummy namespace from pre-7.3 source */
7889         if (strlen(nspinfo->dobj.name) == 0)
7890                 return;
7891
7892         q = createPQExpBuffer();
7893         delq = createPQExpBuffer();
7894         labelq = createPQExpBuffer();
7895
7896         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7897
7898         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7899
7900         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7901
7902         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7903
7904         if (binary_upgrade)
7905                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7906
7907         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7908                                  nspinfo->dobj.name,
7909                                  NULL, NULL,
7910                                  nspinfo->rolname,
7911                                  false, "SCHEMA", SECTION_PRE_DATA,
7912                                  q->data, delq->data, NULL,
7913                                  NULL, 0,
7914                                  NULL, NULL);
7915
7916         /* Dump Schema Comments and Security Labels */
7917         dumpComment(fout, labelq->data,
7918                                 NULL, nspinfo->rolname,
7919                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7920         dumpSecLabel(fout, labelq->data,
7921                                  NULL, nspinfo->rolname,
7922                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7923
7924         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7925                         qnspname, NULL, nspinfo->dobj.name, NULL,
7926                         nspinfo->rolname, nspinfo->nspacl);
7927
7928         free(qnspname);
7929
7930         destroyPQExpBuffer(q);
7931         destroyPQExpBuffer(delq);
7932         destroyPQExpBuffer(labelq);
7933 }
7934
7935 /*
7936  * dumpExtension
7937  *        writes out to fout the queries to recreate an extension
7938  */
7939 static void
7940 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7941 {
7942         PQExpBuffer q;
7943         PQExpBuffer delq;
7944         PQExpBuffer labelq;
7945         char       *qextname;
7946
7947         /* Skip if not to be dumped */
7948         if (!extinfo->dobj.dump || dataOnly)
7949                 return;
7950
7951         q = createPQExpBuffer();
7952         delq = createPQExpBuffer();
7953         labelq = createPQExpBuffer();
7954
7955         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7956
7957         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7958
7959         if (!binary_upgrade)
7960         {
7961                 /*
7962                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7963                  * problem if the extension already exists in the target database;
7964                  * this is essential for installed-by-default extensions such as
7965                  * plpgsql.
7966                  *
7967                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7968                  * built-in extensions based on their OIDs; see
7969                  * selectDumpableExtension.
7970                  */
7971                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7972                                                   qextname, fmtId(extinfo->namespace));
7973         }
7974         else
7975         {
7976                 int                     i;
7977                 int                     n;
7978
7979                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7980
7981                 /*
7982                  * We unconditionally create the extension, so we must drop it if it
7983                  * exists.      This could happen if the user deleted 'plpgsql' and then
7984                  * readded it, causing its oid to be greater than FirstNormalObjectId.
7985                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
7986                  * and recreating extensions like 'plpgsql'.
7987                  */
7988                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
7989
7990                 appendPQExpBuffer(q,
7991                                                   "SELECT binary_upgrade.create_empty_extension(");
7992                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7993                 appendPQExpBuffer(q, ", ");
7994                 appendStringLiteralAH(q, extinfo->namespace, fout);
7995                 appendPQExpBuffer(q, ", ");
7996                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7997                 appendStringLiteralAH(q, extinfo->extversion, fout);
7998                 appendPQExpBuffer(q, ", ");
7999
8000                 /*
8001                  * Note that we're pushing extconfig (an OID array) back into
8002                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
8003                  * preserved in binary upgrade.
8004                  */
8005                 if (strlen(extinfo->extconfig) > 2)
8006                         appendStringLiteralAH(q, extinfo->extconfig, fout);
8007                 else
8008                         appendPQExpBuffer(q, "NULL");
8009                 appendPQExpBuffer(q, ", ");
8010                 if (strlen(extinfo->extcondition) > 2)
8011                         appendStringLiteralAH(q, extinfo->extcondition, fout);
8012                 else
8013                         appendPQExpBuffer(q, "NULL");
8014                 appendPQExpBuffer(q, ", ");
8015                 appendPQExpBuffer(q, "ARRAY[");
8016                 n = 0;
8017                 for (i = 0; i < extinfo->dobj.nDeps; i++)
8018                 {
8019                         DumpableObject *extobj;
8020
8021                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
8022                         if (extobj && extobj->objType == DO_EXTENSION)
8023                         {
8024                                 if (n++ > 0)
8025                                         appendPQExpBuffer(q, ",");
8026                                 appendStringLiteralAH(q, extobj->name, fout);
8027                         }
8028                 }
8029                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
8030                 appendPQExpBuffer(q, ");\n");
8031         }
8032
8033         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
8034
8035         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
8036                                  extinfo->dobj.name,
8037                                  NULL, NULL,
8038                                  "",
8039                                  false, "EXTENSION", SECTION_PRE_DATA,
8040                                  q->data, delq->data, NULL,
8041                                  NULL, 0,
8042                                  NULL, NULL);
8043
8044         /* Dump Extension Comments and Security Labels */
8045         dumpComment(fout, labelq->data,
8046                                 NULL, "",
8047                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8048         dumpSecLabel(fout, labelq->data,
8049                                  NULL, "",
8050                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8051
8052         free(qextname);
8053
8054         destroyPQExpBuffer(q);
8055         destroyPQExpBuffer(delq);
8056         destroyPQExpBuffer(labelq);
8057 }
8058
8059 /*
8060  * dumpType
8061  *        writes out to fout the queries to recreate a user-defined type
8062  */
8063 static void
8064 dumpType(Archive *fout, TypeInfo *tyinfo)
8065 {
8066         /* Skip if not to be dumped */
8067         if (!tyinfo->dobj.dump || dataOnly)
8068                 return;
8069
8070         /* Dump out in proper style */
8071         if (tyinfo->typtype == TYPTYPE_BASE)
8072                 dumpBaseType(fout, tyinfo);
8073         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
8074                 dumpDomain(fout, tyinfo);
8075         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
8076                 dumpCompositeType(fout, tyinfo);
8077         else if (tyinfo->typtype == TYPTYPE_ENUM)
8078                 dumpEnumType(fout, tyinfo);
8079         else if (tyinfo->typtype == TYPTYPE_RANGE)
8080                 dumpRangeType(fout, tyinfo);
8081         else
8082                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
8083                                   tyinfo->dobj.name);
8084 }
8085
8086 /*
8087  * dumpEnumType
8088  *        writes out to fout the queries to recreate a user-defined enum type
8089  */
8090 static void
8091 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
8092 {
8093         PQExpBuffer q = createPQExpBuffer();
8094         PQExpBuffer delq = createPQExpBuffer();
8095         PQExpBuffer labelq = createPQExpBuffer();
8096         PQExpBuffer query = createPQExpBuffer();
8097         PGresult   *res;
8098         int                     num,
8099                                 i;
8100         Oid                     enum_oid;
8101         char       *qtypname;
8102         char       *label;
8103
8104         /* Set proper schema search path */
8105         selectSourceSchema(fout, "pg_catalog");
8106
8107         if (fout->remoteVersion >= 90100)
8108                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8109                                                   "FROM pg_catalog.pg_enum "
8110                                                   "WHERE enumtypid = '%u'"
8111                                                   "ORDER BY enumsortorder",
8112                                                   tyinfo->dobj.catId.oid);
8113         else
8114                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8115                                                   "FROM pg_catalog.pg_enum "
8116                                                   "WHERE enumtypid = '%u'"
8117                                                   "ORDER BY oid",
8118                                                   tyinfo->dobj.catId.oid);
8119
8120         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8121
8122         num = PQntuples(res);
8123
8124         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8125
8126         /*
8127          * DROP must be fully qualified in case same name appears in pg_catalog.
8128          * CASCADE shouldn't be required here as for normal types since the I/O
8129          * functions are generic and do not get dropped.
8130          */
8131         appendPQExpBuffer(delq, "DROP TYPE %s.",
8132                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8133         appendPQExpBuffer(delq, "%s;\n",
8134                                           qtypname);
8135
8136         if (binary_upgrade)
8137                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8138                                                                                                  tyinfo->dobj.catId.oid);
8139
8140         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8141                                           qtypname);
8142
8143         if (!binary_upgrade)
8144         {
8145                 /* Labels with server-assigned oids */
8146                 for (i = 0; i < num; i++)
8147                 {
8148                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8149                         if (i > 0)
8150                                 appendPQExpBuffer(q, ",");
8151                         appendPQExpBuffer(q, "\n    ");
8152                         appendStringLiteralAH(q, label, fout);
8153                 }
8154         }
8155
8156         appendPQExpBuffer(q, "\n);\n");
8157
8158         if (binary_upgrade)
8159         {
8160                 /* Labels with dump-assigned (preserved) oids */
8161                 for (i = 0; i < num; i++)
8162                 {
8163                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8164                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8165
8166                         if (i == 0)
8167                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8168                         appendPQExpBuffer(q,
8169                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8170                                                           enum_oid);
8171                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8172                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8173                         appendPQExpBuffer(q, "%s ADD VALUE ",
8174                                                           qtypname);
8175                         appendStringLiteralAH(q, label, fout);
8176                         appendPQExpBuffer(q, ";\n\n");
8177                 }
8178         }
8179
8180         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8181
8182         if (binary_upgrade)
8183                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8184
8185         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8186                                  tyinfo->dobj.name,
8187                                  tyinfo->dobj.namespace->dobj.name,
8188                                  NULL,
8189                                  tyinfo->rolname, false,
8190                                  "TYPE", SECTION_PRE_DATA,
8191                                  q->data, delq->data, NULL,
8192                                  NULL, 0,
8193                                  NULL, NULL);
8194
8195         /* Dump Type Comments and Security Labels */
8196         dumpComment(fout, labelq->data,
8197                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8198                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8199         dumpSecLabel(fout, labelq->data,
8200                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8201                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8202
8203         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8204                         qtypname, NULL, tyinfo->dobj.name,
8205                         tyinfo->dobj.namespace->dobj.name,
8206                         tyinfo->rolname, tyinfo->typacl);
8207
8208         PQclear(res);
8209         destroyPQExpBuffer(q);
8210         destroyPQExpBuffer(delq);
8211         destroyPQExpBuffer(labelq);
8212         destroyPQExpBuffer(query);
8213 }
8214
8215 /*
8216  * dumpRangeType
8217  *        writes out to fout the queries to recreate a user-defined range type
8218  */
8219 static void
8220 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
8221 {
8222         PQExpBuffer q = createPQExpBuffer();
8223         PQExpBuffer delq = createPQExpBuffer();
8224         PQExpBuffer labelq = createPQExpBuffer();
8225         PQExpBuffer query = createPQExpBuffer();
8226         PGresult   *res;
8227         Oid                     collationOid;
8228         char       *qtypname;
8229         char       *procname;
8230
8231         /*
8232          * select appropriate schema to ensure names in CREATE are properly
8233          * qualified
8234          */
8235         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8236
8237         appendPQExpBuffer(query,
8238                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8239                                           "opc.opcname AS opcname, "
8240                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8241                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8242                                           "opc.opcdefault, "
8243                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8244                                           "     ELSE rngcollation END AS collation, "
8245                                           "rngcanonical, rngsubdiff "
8246                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8247                                           "     pg_catalog.pg_opclass opc "
8248                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8249                                           "rngtypid = '%u'",
8250                                           tyinfo->dobj.catId.oid);
8251
8252         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8253
8254         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8255
8256         /*
8257          * DROP must be fully qualified in case same name appears in pg_catalog.
8258          * CASCADE shouldn't be required here as for normal types since the I/O
8259          * functions are generic and do not get dropped.
8260          */
8261         appendPQExpBuffer(delq, "DROP TYPE %s.",
8262                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8263         appendPQExpBuffer(delq, "%s;\n",
8264                                           qtypname);
8265
8266         if (binary_upgrade)
8267                 binary_upgrade_set_type_oids_by_type_oid(fout,
8268                                                                                                  q, tyinfo->dobj.catId.oid);
8269
8270         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8271                                           qtypname);
8272
8273         appendPQExpBuffer(q, "\n    subtype = %s",
8274                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8275
8276         /* print subtype_opclass only if not default for subtype */
8277         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8278         {
8279                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8280                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8281
8282                 /* always schema-qualify, don't try to be smart */
8283                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8284                                                   fmtId(nspname));
8285                 appendPQExpBuffer(q, "%s", fmtId(opcname));
8286         }
8287
8288         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8289         if (OidIsValid(collationOid))
8290         {
8291                 CollInfo   *coll = findCollationByOid(collationOid);
8292
8293                 if (coll)
8294                 {
8295                         /* always schema-qualify, don't try to be smart */
8296                         appendPQExpBuffer(q, ",\n    collation = %s.",
8297                                                           fmtId(coll->dobj.namespace->dobj.name));
8298                         appendPQExpBuffer(q, "%s",
8299                                                           fmtId(coll->dobj.name));
8300                 }
8301         }
8302
8303         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8304         if (strcmp(procname, "-") != 0)
8305                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8306
8307         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8308         if (strcmp(procname, "-") != 0)
8309                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8310
8311         appendPQExpBuffer(q, "\n);\n");
8312
8313         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8314
8315         if (binary_upgrade)
8316                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8317
8318         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8319                                  tyinfo->dobj.name,
8320                                  tyinfo->dobj.namespace->dobj.name,
8321                                  NULL,
8322                                  tyinfo->rolname, false,
8323                                  "TYPE", SECTION_PRE_DATA,
8324                                  q->data, delq->data, NULL,
8325                                  NULL, 0,
8326                                  NULL, NULL);
8327
8328         /* Dump Type Comments and Security Labels */
8329         dumpComment(fout, labelq->data,
8330                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8331                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8332         dumpSecLabel(fout, labelq->data,
8333                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8334                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8335
8336         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8337                         qtypname, NULL, tyinfo->dobj.name,
8338                         tyinfo->dobj.namespace->dobj.name,
8339                         tyinfo->rolname, tyinfo->typacl);
8340
8341         PQclear(res);
8342         destroyPQExpBuffer(q);
8343         destroyPQExpBuffer(delq);
8344         destroyPQExpBuffer(labelq);
8345         destroyPQExpBuffer(query);
8346 }
8347
8348 /*
8349  * dumpBaseType
8350  *        writes out to fout the queries to recreate a user-defined base type
8351  */
8352 static void
8353 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
8354 {
8355         PQExpBuffer q = createPQExpBuffer();
8356         PQExpBuffer delq = createPQExpBuffer();
8357         PQExpBuffer labelq = createPQExpBuffer();
8358         PQExpBuffer query = createPQExpBuffer();
8359         PGresult   *res;
8360         char       *qtypname;
8361         char       *typlen;
8362         char       *typinput;
8363         char       *typoutput;
8364         char       *typreceive;
8365         char       *typsend;
8366         char       *typmodin;
8367         char       *typmodout;
8368         char       *typanalyze;
8369         Oid                     typreceiveoid;
8370         Oid                     typsendoid;
8371         Oid                     typmodinoid;
8372         Oid                     typmodoutoid;
8373         Oid                     typanalyzeoid;
8374         char       *typcategory;
8375         char       *typispreferred;
8376         char       *typdelim;
8377         char       *typbyval;
8378         char       *typalign;
8379         char       *typstorage;
8380         char       *typcollatable;
8381         char       *typdefault;
8382         bool            typdefault_is_literal = false;
8383
8384         /* Set proper schema search path so regproc references list correctly */
8385         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8386
8387         /* Fetch type-specific details */
8388         if (fout->remoteVersion >= 90100)
8389         {
8390                 appendPQExpBuffer(query, "SELECT typlen, "
8391                                                   "typinput, typoutput, typreceive, typsend, "
8392                                                   "typmodin, typmodout, typanalyze, "
8393                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8394                                                   "typsend::pg_catalog.oid AS typsendoid, "
8395                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8396                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8397                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8398                                                   "typcategory, typispreferred, "
8399                                                   "typdelim, typbyval, typalign, typstorage, "
8400                                                   "(typcollation <> 0) AS typcollatable, "
8401                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8402                                                   "FROM pg_catalog.pg_type "
8403                                                   "WHERE oid = '%u'::pg_catalog.oid",
8404                                                   tyinfo->dobj.catId.oid);
8405         }
8406         else if (fout->remoteVersion >= 80400)
8407         {
8408                 appendPQExpBuffer(query, "SELECT typlen, "
8409                                                   "typinput, typoutput, typreceive, typsend, "
8410                                                   "typmodin, typmodout, typanalyze, "
8411                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8412                                                   "typsend::pg_catalog.oid AS typsendoid, "
8413                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8414                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8415                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8416                                                   "typcategory, typispreferred, "
8417                                                   "typdelim, typbyval, typalign, typstorage, "
8418                                                   "false AS typcollatable, "
8419                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8420                                                   "FROM pg_catalog.pg_type "
8421                                                   "WHERE oid = '%u'::pg_catalog.oid",
8422                                                   tyinfo->dobj.catId.oid);
8423         }
8424         else if (fout->remoteVersion >= 80300)
8425         {
8426                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8427                 appendPQExpBuffer(query, "SELECT typlen, "
8428                                                   "typinput, typoutput, typreceive, typsend, "
8429                                                   "typmodin, typmodout, typanalyze, "
8430                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8431                                                   "typsend::pg_catalog.oid AS typsendoid, "
8432                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8433                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8434                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8435                                                   "'U' AS typcategory, false AS typispreferred, "
8436                                                   "typdelim, typbyval, typalign, typstorage, "
8437                                                   "false AS typcollatable, "
8438                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8439                                                   "FROM pg_catalog.pg_type "
8440                                                   "WHERE oid = '%u'::pg_catalog.oid",
8441                                                   tyinfo->dobj.catId.oid);
8442         }
8443         else if (fout->remoteVersion >= 80000)
8444         {
8445                 appendPQExpBuffer(query, "SELECT typlen, "
8446                                                   "typinput, typoutput, typreceive, typsend, "
8447                                                   "'-' AS typmodin, '-' AS typmodout, "
8448                                                   "typanalyze, "
8449                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8450                                                   "typsend::pg_catalog.oid AS typsendoid, "
8451                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8452                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8453                                                   "'U' AS typcategory, false AS typispreferred, "
8454                                                   "typdelim, typbyval, typalign, typstorage, "
8455                                                   "false AS typcollatable, "
8456                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8457                                                   "FROM pg_catalog.pg_type "
8458                                                   "WHERE oid = '%u'::pg_catalog.oid",
8459                                                   tyinfo->dobj.catId.oid);
8460         }
8461         else if (fout->remoteVersion >= 70400)
8462         {
8463                 appendPQExpBuffer(query, "SELECT typlen, "
8464                                                   "typinput, typoutput, typreceive, typsend, "
8465                                                   "'-' AS typmodin, '-' AS typmodout, "
8466                                                   "'-' AS typanalyze, "
8467                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8468                                                   "typsend::pg_catalog.oid AS typsendoid, "
8469                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8470                                                   "0 AS typanalyzeoid, "
8471                                                   "'U' AS typcategory, false AS typispreferred, "
8472                                                   "typdelim, typbyval, typalign, typstorage, "
8473                                                   "false AS typcollatable, "
8474                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8475                                                   "FROM pg_catalog.pg_type "
8476                                                   "WHERE oid = '%u'::pg_catalog.oid",
8477                                                   tyinfo->dobj.catId.oid);
8478         }
8479         else if (fout->remoteVersion >= 70300)
8480         {
8481                 appendPQExpBuffer(query, "SELECT typlen, "
8482                                                   "typinput, typoutput, "
8483                                                   "'-' AS typreceive, '-' AS typsend, "
8484                                                   "'-' AS typmodin, '-' AS typmodout, "
8485                                                   "'-' AS typanalyze, "
8486                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8487                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8488                                                   "0 AS typanalyzeoid, "
8489                                                   "'U' AS typcategory, false AS typispreferred, "
8490                                                   "typdelim, typbyval, typalign, typstorage, "
8491                                                   "false AS typcollatable, "
8492                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8493                                                   "FROM pg_catalog.pg_type "
8494                                                   "WHERE oid = '%u'::pg_catalog.oid",
8495                                                   tyinfo->dobj.catId.oid);
8496         }
8497         else if (fout->remoteVersion >= 70200)
8498         {
8499                 /*
8500                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8501                  * ignore them because they are not right.
8502                  */
8503                 appendPQExpBuffer(query, "SELECT typlen, "
8504                                                   "typinput, typoutput, "
8505                                                   "'-' AS typreceive, '-' AS typsend, "
8506                                                   "'-' AS typmodin, '-' AS typmodout, "
8507                                                   "'-' AS typanalyze, "
8508                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8509                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8510                                                   "0 AS typanalyzeoid, "
8511                                                   "'U' AS typcategory, false AS typispreferred, "
8512                                                   "typdelim, typbyval, typalign, typstorage, "
8513                                                   "false AS typcollatable, "
8514                                                   "NULL AS typdefaultbin, typdefault "
8515                                                   "FROM pg_type "
8516                                                   "WHERE oid = '%u'::oid",
8517                                                   tyinfo->dobj.catId.oid);
8518         }
8519         else if (fout->remoteVersion >= 70100)
8520         {
8521                 /*
8522                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8523                  * representation.
8524                  */
8525                 appendPQExpBuffer(query, "SELECT typlen, "
8526                                                   "typinput, typoutput, "
8527                                                   "'-' AS typreceive, '-' AS typsend, "
8528                                                   "'-' AS typmodin, '-' AS typmodout, "
8529                                                   "'-' AS typanalyze, "
8530                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8531                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8532                                                   "0 AS typanalyzeoid, "
8533                                                   "'U' AS typcategory, false AS typispreferred, "
8534                                                   "typdelim, typbyval, typalign, typstorage, "
8535                                                   "false AS typcollatable, "
8536                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8537                                                   "FROM pg_type "
8538                                                   "WHERE oid = '%u'::oid",
8539                                                   tyinfo->dobj.catId.oid);
8540         }
8541         else
8542         {
8543                 appendPQExpBuffer(query, "SELECT typlen, "
8544                                                   "typinput, typoutput, "
8545                                                   "'-' AS typreceive, '-' AS typsend, "
8546                                                   "'-' AS typmodin, '-' AS typmodout, "
8547                                                   "'-' AS typanalyze, "
8548                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8549                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8550                                                   "0 AS typanalyzeoid, "
8551                                                   "'U' AS typcategory, false AS typispreferred, "
8552                                                   "typdelim, typbyval, typalign, "
8553                                                   "'p'::char AS typstorage, "
8554                                                   "false AS typcollatable, "
8555                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8556                                                   "FROM pg_type "
8557                                                   "WHERE oid = '%u'::oid",
8558                                                   tyinfo->dobj.catId.oid);
8559         }
8560
8561         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8562
8563         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8564         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8565         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8566         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8567         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8568         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8569         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8570         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8571         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8572         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8573         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8574         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8575         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8576         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8577         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8578         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8579         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8580         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8581         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8582         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8583         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8584                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8585         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8586         {
8587                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8588                 typdefault_is_literal = true;   /* it needs quotes */
8589         }
8590         else
8591                 typdefault = NULL;
8592
8593         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8594
8595         /*
8596          * DROP must be fully qualified in case same name appears in pg_catalog.
8597          * The reason we include CASCADE is that the circular dependency between
8598          * the type and its I/O functions makes it impossible to drop the type any
8599          * other way.
8600          */
8601         appendPQExpBuffer(delq, "DROP TYPE %s.",
8602                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8603         appendPQExpBuffer(delq, "%s CASCADE;\n",
8604                                           qtypname);
8605
8606         /* We might already have a shell type, but setting pg_type_oid is harmless */
8607         if (binary_upgrade)
8608                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8609                                                                                                  tyinfo->dobj.catId.oid);
8610
8611         appendPQExpBuffer(q,
8612                                           "CREATE TYPE %s (\n"
8613                                           "    INTERNALLENGTH = %s",
8614                                           qtypname,
8615                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8616
8617         if (fout->remoteVersion >= 70300)
8618         {
8619                 /* regproc result is correctly quoted as of 7.3 */
8620                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8621                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8622                 if (OidIsValid(typreceiveoid))
8623                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8624                 if (OidIsValid(typsendoid))
8625                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8626                 if (OidIsValid(typmodinoid))
8627                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8628                 if (OidIsValid(typmodoutoid))
8629                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8630                 if (OidIsValid(typanalyzeoid))
8631                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8632         }
8633         else
8634         {
8635                 /* regproc delivers an unquoted name before 7.3 */
8636                 /* cannot combine these because fmtId uses static result area */
8637                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8638                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8639                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8640         }
8641
8642         if (strcmp(typcollatable, "t") == 0)
8643                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8644
8645         if (typdefault != NULL)
8646         {
8647                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8648                 if (typdefault_is_literal)
8649                         appendStringLiteralAH(q, typdefault, fout);
8650                 else
8651                         appendPQExpBufferStr(q, typdefault);
8652         }
8653
8654         if (OidIsValid(tyinfo->typelem))
8655         {
8656                 char       *elemType;
8657
8658                 /* reselect schema in case changed by function dump */
8659                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8660                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8661                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8662                 free(elemType);
8663         }
8664
8665         if (strcmp(typcategory, "U") != 0)
8666         {
8667                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8668                 appendStringLiteralAH(q, typcategory, fout);
8669         }
8670
8671         if (strcmp(typispreferred, "t") == 0)
8672                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8673
8674         if (typdelim && strcmp(typdelim, ",") != 0)
8675         {
8676                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8677                 appendStringLiteralAH(q, typdelim, fout);
8678         }
8679
8680         if (strcmp(typalign, "c") == 0)
8681                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8682         else if (strcmp(typalign, "s") == 0)
8683                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8684         else if (strcmp(typalign, "i") == 0)
8685                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8686         else if (strcmp(typalign, "d") == 0)
8687                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8688
8689         if (strcmp(typstorage, "p") == 0)
8690                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8691         else if (strcmp(typstorage, "e") == 0)
8692                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8693         else if (strcmp(typstorage, "x") == 0)
8694                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8695         else if (strcmp(typstorage, "m") == 0)
8696                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8697
8698         if (strcmp(typbyval, "t") == 0)
8699                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8700
8701         appendPQExpBuffer(q, "\n);\n");
8702
8703         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8704
8705         if (binary_upgrade)
8706                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8707
8708         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8709                                  tyinfo->dobj.name,
8710                                  tyinfo->dobj.namespace->dobj.name,
8711                                  NULL,
8712                                  tyinfo->rolname, false,
8713                                  "TYPE", SECTION_PRE_DATA,
8714                                  q->data, delq->data, NULL,
8715                                  NULL, 0,
8716                                  NULL, NULL);
8717
8718         /* Dump Type Comments and Security Labels */
8719         dumpComment(fout, labelq->data,
8720                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8721                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8722         dumpSecLabel(fout, labelq->data,
8723                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8724                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8725
8726         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8727                         qtypname, NULL, tyinfo->dobj.name,
8728                         tyinfo->dobj.namespace->dobj.name,
8729                         tyinfo->rolname, tyinfo->typacl);
8730
8731         PQclear(res);
8732         destroyPQExpBuffer(q);
8733         destroyPQExpBuffer(delq);
8734         destroyPQExpBuffer(labelq);
8735         destroyPQExpBuffer(query);
8736 }
8737
8738 /*
8739  * dumpDomain
8740  *        writes out to fout the queries to recreate a user-defined domain
8741  */
8742 static void
8743 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8744 {
8745         PQExpBuffer q = createPQExpBuffer();
8746         PQExpBuffer delq = createPQExpBuffer();
8747         PQExpBuffer labelq = createPQExpBuffer();
8748         PQExpBuffer query = createPQExpBuffer();
8749         PGresult   *res;
8750         int                     i;
8751         char       *qtypname;
8752         char       *typnotnull;
8753         char       *typdefn;
8754         char       *typdefault;
8755         Oid                     typcollation;
8756         bool            typdefault_is_literal = false;
8757
8758         /* Set proper schema search path so type references list correctly */
8759         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8760
8761         /* Fetch domain specific details */
8762         if (fout->remoteVersion >= 90100)
8763         {
8764                 /* typcollation is new in 9.1 */
8765                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8766                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8767                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8768                                                   "t.typdefault, "
8769                                                   "CASE WHEN t.typcollation <> u.typcollation "
8770                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8771                                                   "FROM pg_catalog.pg_type t "
8772                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8773                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8774                                                   tyinfo->dobj.catId.oid);
8775         }
8776         else
8777         {
8778                 /* We assume here that remoteVersion must be at least 70300 */
8779                 appendPQExpBuffer(query, "SELECT typnotnull, "
8780                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8781                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8782                                                   "typdefault, 0 AS typcollation "
8783                                                   "FROM pg_catalog.pg_type "
8784                                                   "WHERE oid = '%u'::pg_catalog.oid",
8785                                                   tyinfo->dobj.catId.oid);
8786         }
8787
8788         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8789
8790         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8791         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8792         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8793                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8794         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8795         {
8796                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8797                 typdefault_is_literal = true;   /* it needs quotes */
8798         }
8799         else
8800                 typdefault = NULL;
8801         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8802
8803         if (binary_upgrade)
8804                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8805                                                                                                  tyinfo->dobj.catId.oid);
8806
8807         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8808
8809         appendPQExpBuffer(q,
8810                                           "CREATE DOMAIN %s AS %s",
8811                                           qtypname,
8812                                           typdefn);
8813
8814         /* Print collation only if different from base type's collation */
8815         if (OidIsValid(typcollation))
8816         {
8817                 CollInfo   *coll;
8818
8819                 coll = findCollationByOid(typcollation);
8820                 if (coll)
8821                 {
8822                         /* always schema-qualify, don't try to be smart */
8823                         appendPQExpBuffer(q, " COLLATE %s.",
8824                                                           fmtId(coll->dobj.namespace->dobj.name));
8825                         appendPQExpBuffer(q, "%s",
8826                                                           fmtId(coll->dobj.name));
8827                 }
8828         }
8829
8830         if (typnotnull[0] == 't')
8831                 appendPQExpBuffer(q, " NOT NULL");
8832
8833         if (typdefault != NULL)
8834         {
8835                 appendPQExpBuffer(q, " DEFAULT ");
8836                 if (typdefault_is_literal)
8837                         appendStringLiteralAH(q, typdefault, fout);
8838                 else
8839                         appendPQExpBufferStr(q, typdefault);
8840         }
8841
8842         PQclear(res);
8843
8844         /*
8845          * Add any CHECK constraints for the domain
8846          */
8847         for (i = 0; i < tyinfo->nDomChecks; i++)
8848         {
8849                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8850
8851                 if (!domcheck->separate)
8852                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8853                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8854         }
8855
8856         appendPQExpBuffer(q, ";\n");
8857
8858         /*
8859          * DROP must be fully qualified in case same name appears in pg_catalog
8860          */
8861         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8862                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8863         appendPQExpBuffer(delq, "%s;\n",
8864                                           qtypname);
8865
8866         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
8867
8868         if (binary_upgrade)
8869                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8870
8871         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8872                                  tyinfo->dobj.name,
8873                                  tyinfo->dobj.namespace->dobj.name,
8874                                  NULL,
8875                                  tyinfo->rolname, false,
8876                                  "DOMAIN", SECTION_PRE_DATA,
8877                                  q->data, delq->data, NULL,
8878                                  NULL, 0,
8879                                  NULL, NULL);
8880
8881         /* Dump Domain Comments and Security Labels */
8882         dumpComment(fout, labelq->data,
8883                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8884                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8885         dumpSecLabel(fout, labelq->data,
8886                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8887                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8888
8889         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8890                         qtypname, NULL, tyinfo->dobj.name,
8891                         tyinfo->dobj.namespace->dobj.name,
8892                         tyinfo->rolname, tyinfo->typacl);
8893
8894         destroyPQExpBuffer(q);
8895         destroyPQExpBuffer(delq);
8896         destroyPQExpBuffer(labelq);
8897         destroyPQExpBuffer(query);
8898 }
8899
8900 /*
8901  * dumpCompositeType
8902  *        writes out to fout the queries to recreate a user-defined stand-alone
8903  *        composite type
8904  */
8905 static void
8906 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8907 {
8908         PQExpBuffer q = createPQExpBuffer();
8909         PQExpBuffer dropped = createPQExpBuffer();
8910         PQExpBuffer delq = createPQExpBuffer();
8911         PQExpBuffer labelq = createPQExpBuffer();
8912         PQExpBuffer query = createPQExpBuffer();
8913         PGresult   *res;
8914         char       *qtypname;
8915         int                     ntups;
8916         int                     i_attname;
8917         int                     i_atttypdefn;
8918         int                     i_attlen;
8919         int                     i_attalign;
8920         int                     i_attisdropped;
8921         int                     i_attcollation;
8922         int                     i_typrelid;
8923         int                     i;
8924         int                     actual_atts;
8925
8926         /* Set proper schema search path so type references list correctly */
8927         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8928
8929         /* Fetch type specific details */
8930         if (fout->remoteVersion >= 90100)
8931         {
8932                 /*
8933                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8934                  * clauses for attributes whose collation is different from their
8935                  * type's default, we use a CASE here to suppress uninteresting
8936                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8937                  * collation does not matter for those.
8938                  */
8939                 appendPQExpBuffer(query, "SELECT a.attname, "
8940                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8941                                                   "a.attlen, a.attalign, a.attisdropped, "
8942                                                   "CASE WHEN a.attcollation <> at.typcollation "
8943                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8944                                                   "ct.typrelid "
8945                                                   "FROM pg_catalog.pg_type ct "
8946                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8947                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8948                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8949                                                   "ORDER BY a.attnum ",
8950                                                   tyinfo->dobj.catId.oid);
8951         }
8952         else
8953         {
8954                 /*
8955                  * We assume here that remoteVersion must be at least 70300.  Since
8956                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8957                  * always be false.
8958                  */
8959                 appendPQExpBuffer(query, "SELECT a.attname, "
8960                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8961                                                   "a.attlen, a.attalign, a.attisdropped, "
8962                                                   "0 AS attcollation, "
8963                                                   "ct.typrelid "
8964                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8965                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8966                                                   "AND a.attrelid = ct.typrelid "
8967                                                   "ORDER BY a.attnum ",
8968                                                   tyinfo->dobj.catId.oid);
8969         }
8970
8971         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8972
8973         ntups = PQntuples(res);
8974
8975         i_attname = PQfnumber(res, "attname");
8976         i_atttypdefn = PQfnumber(res, "atttypdefn");
8977         i_attlen = PQfnumber(res, "attlen");
8978         i_attalign = PQfnumber(res, "attalign");
8979         i_attisdropped = PQfnumber(res, "attisdropped");
8980         i_attcollation = PQfnumber(res, "attcollation");
8981         i_typrelid = PQfnumber(res, "typrelid");
8982
8983         if (binary_upgrade)
8984         {
8985                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8986
8987                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8988                                                                                                  tyinfo->dobj.catId.oid);
8989                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
8990         }
8991
8992         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8993
8994         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8995                                           qtypname);
8996
8997         actual_atts = 0;
8998         for (i = 0; i < ntups; i++)
8999         {
9000                 char       *attname;
9001                 char       *atttypdefn;
9002                 char       *attlen;
9003                 char       *attalign;
9004                 bool            attisdropped;
9005                 Oid                     attcollation;
9006
9007                 attname = PQgetvalue(res, i, i_attname);
9008                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
9009                 attlen = PQgetvalue(res, i, i_attlen);
9010                 attalign = PQgetvalue(res, i, i_attalign);
9011                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
9012                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
9013
9014                 if (attisdropped && !binary_upgrade)
9015                         continue;
9016
9017                 /* Format properly if not first attr */
9018                 if (actual_atts++ > 0)
9019                         appendPQExpBuffer(q, ",");
9020                 appendPQExpBuffer(q, "\n\t");
9021
9022                 if (!attisdropped)
9023                 {
9024                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
9025
9026                         /* Add collation if not default for the column type */
9027                         if (OidIsValid(attcollation))
9028                         {
9029                                 CollInfo   *coll;
9030
9031                                 coll = findCollationByOid(attcollation);
9032                                 if (coll)
9033                                 {
9034                                         /* always schema-qualify, don't try to be smart */
9035                                         appendPQExpBuffer(q, " COLLATE %s.",
9036                                                                           fmtId(coll->dobj.namespace->dobj.name));
9037                                         appendPQExpBuffer(q, "%s",
9038                                                                           fmtId(coll->dobj.name));
9039                                 }
9040                         }
9041                 }
9042                 else
9043                 {
9044                         /*
9045                          * This is a dropped attribute and we're in binary_upgrade mode.
9046                          * Insert a placeholder for it in the CREATE TYPE command, and set
9047                          * length and alignment with direct UPDATE to the catalogs
9048                          * afterwards. See similar code in dumpTableSchema().
9049                          */
9050                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
9051
9052                         /* stash separately for insertion after the CREATE TYPE */
9053                         appendPQExpBuffer(dropped,
9054                                           "\n-- For binary upgrade, recreate dropped column.\n");
9055                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
9056                                                           "SET attlen = %s, "
9057                                                           "attalign = '%s', attbyval = false\n"
9058                                                           "WHERE attname = ", attlen, attalign);
9059                         appendStringLiteralAH(dropped, attname, fout);
9060                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
9061                         appendStringLiteralAH(dropped, qtypname, fout);
9062                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
9063
9064                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
9065                                                           qtypname);
9066                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
9067                                                           fmtId(attname));
9068                 }
9069         }
9070         appendPQExpBuffer(q, "\n);\n");
9071         appendPQExpBufferStr(q, dropped->data);
9072
9073         /*
9074          * DROP must be fully qualified in case same name appears in pg_catalog
9075          */
9076         appendPQExpBuffer(delq, "DROP TYPE %s.",
9077                                           fmtId(tyinfo->dobj.namespace->dobj.name));
9078         appendPQExpBuffer(delq, "%s;\n",
9079                                           qtypname);
9080
9081         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
9082
9083         if (binary_upgrade)
9084                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9085
9086         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9087                                  tyinfo->dobj.name,
9088                                  tyinfo->dobj.namespace->dobj.name,
9089                                  NULL,
9090                                  tyinfo->rolname, false,
9091                                  "TYPE", SECTION_PRE_DATA,
9092                                  q->data, delq->data, NULL,
9093                                  NULL, 0,
9094                                  NULL, NULL);
9095
9096
9097         /* Dump Type Comments and Security Labels */
9098         dumpComment(fout, labelq->data,
9099                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9100                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9101         dumpSecLabel(fout, labelq->data,
9102                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9103                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9104
9105         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9106                         qtypname, NULL, tyinfo->dobj.name,
9107                         tyinfo->dobj.namespace->dobj.name,
9108                         tyinfo->rolname, tyinfo->typacl);
9109
9110         PQclear(res);
9111         destroyPQExpBuffer(q);
9112         destroyPQExpBuffer(dropped);
9113         destroyPQExpBuffer(delq);
9114         destroyPQExpBuffer(labelq);
9115         destroyPQExpBuffer(query);
9116
9117         /* Dump any per-column comments */
9118         dumpCompositeTypeColComments(fout, tyinfo);
9119 }
9120
9121 /*
9122  * dumpCompositeTypeColComments
9123  *        writes out to fout the queries to recreate comments on the columns of
9124  *        a user-defined stand-alone composite type
9125  */
9126 static void
9127 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9128 {
9129         CommentItem *comments;
9130         int                     ncomments;
9131         PGresult   *res;
9132         PQExpBuffer query;
9133         PQExpBuffer target;
9134         Oid                     pgClassOid;
9135         int                     i;
9136         int                     ntups;
9137         int                     i_attname;
9138         int                     i_attnum;
9139
9140         query = createPQExpBuffer();
9141
9142         /* We assume here that remoteVersion must be at least 70300 */
9143         appendPQExpBuffer(query,
9144                                           "SELECT c.tableoid, a.attname, a.attnum "
9145                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9146                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9147                                           "  AND NOT a.attisdropped "
9148                                           "ORDER BY a.attnum ",
9149                                           tyinfo->typrelid);
9150
9151         /* Fetch column attnames */
9152         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9153
9154         ntups = PQntuples(res);
9155         if (ntups < 1)
9156         {
9157                 PQclear(res);
9158                 destroyPQExpBuffer(query);
9159                 return;
9160         }
9161
9162         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9163
9164         /* Search for comments associated with type's pg_class OID */
9165         ncomments = findComments(fout,
9166                                                          pgClassOid,
9167                                                          tyinfo->typrelid,
9168                                                          &comments);
9169
9170         /* If no comments exist, we're done */
9171         if (ncomments <= 0)
9172         {
9173                 PQclear(res);
9174                 destroyPQExpBuffer(query);
9175                 return;
9176         }
9177
9178         /* Build COMMENT ON statements */
9179         target = createPQExpBuffer();
9180
9181         i_attnum = PQfnumber(res, "attnum");
9182         i_attname = PQfnumber(res, "attname");
9183         while (ncomments > 0)
9184         {
9185                 const char *attname;
9186
9187                 attname = NULL;
9188                 for (i = 0; i < ntups; i++)
9189                 {
9190                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9191                         {
9192                                 attname = PQgetvalue(res, i, i_attname);
9193                                 break;
9194                         }
9195                 }
9196                 if (attname)                    /* just in case we don't find it */
9197                 {
9198                         const char *descr = comments->descr;
9199
9200                         resetPQExpBuffer(target);
9201                         appendPQExpBuffer(target, "COLUMN %s.",
9202                                                           fmtId(tyinfo->dobj.name));
9203                         appendPQExpBuffer(target, "%s",
9204                                                           fmtId(attname));
9205
9206                         resetPQExpBuffer(query);
9207                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9208                         appendStringLiteralAH(query, descr, fout);
9209                         appendPQExpBuffer(query, ";\n");
9210
9211                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9212                                                  target->data,
9213                                                  tyinfo->dobj.namespace->dobj.name,
9214                                                  NULL, tyinfo->rolname,
9215                                                  false, "COMMENT", SECTION_NONE,
9216                                                  query->data, "", NULL,
9217                                                  &(tyinfo->dobj.dumpId), 1,
9218                                                  NULL, NULL);
9219                 }
9220
9221                 comments++;
9222                 ncomments--;
9223         }
9224
9225         PQclear(res);
9226         destroyPQExpBuffer(query);
9227         destroyPQExpBuffer(target);
9228 }
9229
9230 /*
9231  * dumpShellType
9232  *        writes out to fout the queries to create a shell type
9233  *
9234  * We dump a shell definition in advance of the I/O functions for the type.
9235  */
9236 static void
9237 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
9238 {
9239         PQExpBuffer q;
9240
9241         /* Skip if not to be dumped */
9242         if (!stinfo->dobj.dump || dataOnly)
9243                 return;
9244
9245         q = createPQExpBuffer();
9246
9247         /*
9248          * Note the lack of a DROP command for the shell type; any required DROP
9249          * is driven off the base type entry, instead.  This interacts with
9250          * _printTocEntry()'s use of the presence of a DROP command to decide
9251          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9252          * the shell type's owner immediately on creation; that should happen only
9253          * after it's filled in, otherwise the backend complains.
9254          */
9255
9256         if (binary_upgrade)
9257                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9258                                                                                    stinfo->baseType->dobj.catId.oid);
9259
9260         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9261                                           fmtId(stinfo->dobj.name));
9262
9263         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9264                                  stinfo->dobj.name,
9265                                  stinfo->dobj.namespace->dobj.name,
9266                                  NULL,
9267                                  stinfo->baseType->rolname, false,
9268                                  "SHELL TYPE", SECTION_PRE_DATA,
9269                                  q->data, "", NULL,
9270                                  NULL, 0,
9271                                  NULL, NULL);
9272
9273         destroyPQExpBuffer(q);
9274 }
9275
9276 /*
9277  * Determine whether we want to dump definitions for procedural languages.
9278  * Since the languages themselves don't have schemas, we can't rely on
9279  * the normal schema-based selection mechanism.  We choose to dump them
9280  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9281  * the dump flag of the PL's call handler function, but in 8.1 this will
9282  * probably always be false since call handlers are created in pg_catalog.)
9283  *
9284  * For some backwards compatibility with the older behavior, we forcibly
9285  * dump a PL if its handler function (and validator if any) are in a
9286  * dumpable namespace.  That case is not checked here.
9287  *
9288  * Also, if the PL belongs to an extension, we do not use this heuristic.
9289  * That case isn't checked here either.
9290  */
9291 static bool
9292 shouldDumpProcLangs(void)
9293 {
9294         if (!include_everything)
9295                 return false;
9296         /* And they're schema not data */
9297         if (dataOnly)
9298                 return false;
9299         return true;
9300 }
9301
9302 /*
9303  * dumpProcLang
9304  *                writes out to fout the queries to recreate a user-defined
9305  *                procedural language
9306  */
9307 static void
9308 dumpProcLang(Archive *fout, ProcLangInfo *plang)
9309 {
9310         PQExpBuffer defqry;
9311         PQExpBuffer delqry;
9312         PQExpBuffer labelq;
9313         bool            useParams;
9314         char       *qlanname;
9315         char       *lanschema;
9316         FuncInfo   *funcInfo;
9317         FuncInfo   *inlineInfo = NULL;
9318         FuncInfo   *validatorInfo = NULL;
9319
9320         /* Skip if not to be dumped */
9321         if (!plang->dobj.dump || dataOnly)
9322                 return;
9323
9324         /*
9325          * Try to find the support function(s).  It is not an error if we don't
9326          * find them --- if the functions are in the pg_catalog schema, as is
9327          * standard in 8.1 and up, then we won't have loaded them. (In this case
9328          * we will emit a parameterless CREATE LANGUAGE command, which will
9329          * require PL template knowledge in the backend to reload.)
9330          */
9331
9332         funcInfo = findFuncByOid(plang->lanplcallfoid);
9333         if (funcInfo != NULL && !funcInfo->dobj.dump)
9334                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9335
9336         if (OidIsValid(plang->laninline))
9337         {
9338                 inlineInfo = findFuncByOid(plang->laninline);
9339                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9340                         inlineInfo = NULL;
9341         }
9342
9343         if (OidIsValid(plang->lanvalidator))
9344         {
9345                 validatorInfo = findFuncByOid(plang->lanvalidator);
9346                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9347                         validatorInfo = NULL;
9348         }
9349
9350         /*
9351          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9352          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9353          * dump it.
9354          *
9355          * However, for a language that belongs to an extension, we must not use
9356          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9357          * told to (via dobj.dump).  Generally the support functions will belong
9358          * to the same extension and so have the same dump flags ... if they
9359          * don't, this might not work terribly nicely.
9360          */
9361         useParams = (funcInfo != NULL &&
9362                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9363                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9364
9365         if (!plang->dobj.ext_member)
9366         {
9367                 if (!useParams && !shouldDumpProcLangs())
9368                         return;
9369         }
9370
9371         defqry = createPQExpBuffer();
9372         delqry = createPQExpBuffer();
9373         labelq = createPQExpBuffer();
9374
9375         qlanname = pg_strdup(fmtId(plang->dobj.name));
9376
9377         /*
9378          * If dumping a HANDLER clause, treat the language as being in the handler
9379          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9380          * it doesn't really have a schema.
9381          */
9382         if (useParams)
9383                 lanschema = funcInfo->dobj.namespace->dobj.name;
9384         else
9385                 lanschema = NULL;
9386
9387         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9388                                           qlanname);
9389
9390         if (useParams)
9391         {
9392                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9393                                                   plang->lanpltrusted ? "TRUSTED " : "",
9394                                                   qlanname);
9395                 appendPQExpBuffer(defqry, " HANDLER %s",
9396                                                   fmtId(funcInfo->dobj.name));
9397                 if (OidIsValid(plang->laninline))
9398                 {
9399                         appendPQExpBuffer(defqry, " INLINE ");
9400                         /* Cope with possibility that inline is in different schema */
9401                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9402                                 appendPQExpBuffer(defqry, "%s.",
9403                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9404                         appendPQExpBuffer(defqry, "%s",
9405                                                           fmtId(inlineInfo->dobj.name));
9406                 }
9407                 if (OidIsValid(plang->lanvalidator))
9408                 {
9409                         appendPQExpBuffer(defqry, " VALIDATOR ");
9410                         /* Cope with possibility that validator is in different schema */
9411                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9412                                 appendPQExpBuffer(defqry, "%s.",
9413                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9414                         appendPQExpBuffer(defqry, "%s",
9415                                                           fmtId(validatorInfo->dobj.name));
9416                 }
9417         }
9418         else
9419         {
9420                 /*
9421                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9422                  * command will not fail if the language is preinstalled in the target
9423                  * database.  We restrict the use of REPLACE to this case so as to
9424                  * eliminate the risk of replacing a language with incompatible
9425                  * parameter settings: this command will only succeed at all if there
9426                  * is a pg_pltemplate entry, and if there is one, the existing entry
9427                  * must match it too.
9428                  */
9429                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9430                                                   qlanname);
9431         }
9432         appendPQExpBuffer(defqry, ";\n");
9433
9434         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9435
9436         if (binary_upgrade)
9437                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9438
9439         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9440                                  plang->dobj.name,
9441                                  lanschema, NULL, plang->lanowner,
9442                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9443                                  defqry->data, delqry->data, NULL,
9444                                  NULL, 0,
9445                                  NULL, NULL);
9446
9447         /* Dump Proc Lang Comments and Security Labels */
9448         dumpComment(fout, labelq->data,
9449                                 NULL, "",
9450                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9451         dumpSecLabel(fout, labelq->data,
9452                                  NULL, "",
9453                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9454
9455         if (plang->lanpltrusted)
9456                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9457                                 qlanname, NULL, plang->dobj.name,
9458                                 lanschema,
9459                                 plang->lanowner, plang->lanacl);
9460
9461         free(qlanname);
9462
9463         destroyPQExpBuffer(defqry);
9464         destroyPQExpBuffer(delqry);
9465         destroyPQExpBuffer(labelq);
9466 }
9467
9468 /*
9469  * format_function_arguments: generate function name and argument list
9470  *
9471  * This is used when we can rely on pg_get_function_arguments to format
9472  * the argument list.  Note, however, that pg_get_function_arguments
9473  * does not special-case zero-argument aggregates.
9474  */
9475 static char *
9476 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
9477 {
9478         PQExpBufferData fn;
9479
9480         initPQExpBuffer(&fn);
9481         appendPQExpBuffer(&fn, "%s", fmtId(finfo->dobj.name));
9482         if (is_agg && finfo->nargs == 0)
9483                 appendPQExpBuffer(&fn, "(*)");
9484         else
9485                 appendPQExpBuffer(&fn, "(%s)", funcargs);
9486         return fn.data;
9487 }
9488
9489 /*
9490  * format_function_arguments_old: generate function name and argument list
9491  *
9492  * The argument type names are qualified if needed.  The function name
9493  * is never qualified.
9494  *
9495  * This is used only with pre-8.4 servers, so we aren't expecting to see
9496  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9497  *
9498  * Any or all of allargtypes, argmodes, argnames may be NULL.
9499  */
9500 static char *
9501 format_function_arguments_old(Archive *fout,
9502                                                           FuncInfo *finfo, int nallargs,
9503                                                           char **allargtypes,
9504                                                           char **argmodes,
9505                                                           char **argnames)
9506 {
9507         PQExpBufferData fn;
9508         int                     j;
9509
9510         initPQExpBuffer(&fn);
9511         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9512         for (j = 0; j < nallargs; j++)
9513         {
9514                 Oid                     typid;
9515                 char       *typname;
9516                 const char *argmode;
9517                 const char *argname;
9518
9519                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9520                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9521
9522                 if (argmodes)
9523                 {
9524                         switch (argmodes[j][0])
9525                         {
9526                                 case PROARGMODE_IN:
9527                                         argmode = "";
9528                                         break;
9529                                 case PROARGMODE_OUT:
9530                                         argmode = "OUT ";
9531                                         break;
9532                                 case PROARGMODE_INOUT:
9533                                         argmode = "INOUT ";
9534                                         break;
9535                                 default:
9536                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9537                                         argmode = "";
9538                                         break;
9539                         }
9540                 }
9541                 else
9542                         argmode = "";
9543
9544                 argname = argnames ? argnames[j] : (char *) NULL;
9545                 if (argname && argname[0] == '\0')
9546                         argname = NULL;
9547
9548                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9549                                                   (j > 0) ? ", " : "",
9550                                                   argmode,
9551                                                   argname ? fmtId(argname) : "",
9552                                                   argname ? " " : "",
9553                                                   typname);
9554                 free(typname);
9555         }
9556         appendPQExpBuffer(&fn, ")");
9557         return fn.data;
9558 }
9559
9560 /*
9561  * format_function_signature: generate function name and argument list
9562  *
9563  * This is like format_function_arguments_old except that only a minimal
9564  * list of input argument types is generated; this is sufficient to
9565  * reference the function, but not to define it.
9566  *
9567  * If honor_quotes is false then the function name is never quoted.
9568  * This is appropriate for use in TOC tags, but not in SQL commands.
9569  */
9570 static char *
9571 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9572 {
9573         PQExpBufferData fn;
9574         int                     j;
9575
9576         initPQExpBuffer(&fn);
9577         if (honor_quotes)
9578                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9579         else
9580                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9581         for (j = 0; j < finfo->nargs; j++)
9582         {
9583                 char       *typname;
9584
9585                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9586                                                                            zeroAsOpaque);
9587
9588                 appendPQExpBuffer(&fn, "%s%s",
9589                                                   (j > 0) ? ", " : "",
9590                                                   typname);
9591                 free(typname);
9592         }
9593         appendPQExpBuffer(&fn, ")");
9594         return fn.data;
9595 }
9596
9597
9598 /*
9599  * dumpFunc:
9600  *        dump out one function
9601  */
9602 static void
9603 dumpFunc(Archive *fout, FuncInfo *finfo)
9604 {
9605         PQExpBuffer query;
9606         PQExpBuffer q;
9607         PQExpBuffer delqry;
9608         PQExpBuffer labelq;
9609         PQExpBuffer asPart;
9610         PGresult   *res;
9611         char       *funcsig;            /* identity signature */
9612         char       *funcfullsig;        /* full signature */
9613         char       *funcsig_tag;
9614         char       *proretset;
9615         char       *prosrc;
9616         char       *probin;
9617         char       *funcargs;
9618         char       *funciargs;
9619         char       *funcresult;
9620         char       *proallargtypes;
9621         char       *proargmodes;
9622         char       *proargnames;
9623         char       *proiswindow;
9624         char       *provolatile;
9625         char       *proisstrict;
9626         char       *prosecdef;
9627         char       *proleakproof;
9628         char       *proconfig;
9629         char       *procost;
9630         char       *prorows;
9631         char       *lanname;
9632         char       *rettypename;
9633         int                     nallargs;
9634         char      **allargtypes = NULL;
9635         char      **argmodes = NULL;
9636         char      **argnames = NULL;
9637         char      **configitems = NULL;
9638         int                     nconfigitems = 0;
9639         int                     i;
9640
9641         /* Skip if not to be dumped */
9642         if (!finfo->dobj.dump || dataOnly)
9643                 return;
9644
9645         query = createPQExpBuffer();
9646         q = createPQExpBuffer();
9647         delqry = createPQExpBuffer();
9648         labelq = createPQExpBuffer();
9649         asPart = createPQExpBuffer();
9650
9651         /* Set proper schema search path so type references list correctly */
9652         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9653
9654         /* Fetch function-specific details */
9655         if (fout->remoteVersion >= 90200)
9656         {
9657                 /*
9658                  * proleakproof was added at v9.2
9659                  */
9660                 appendPQExpBuffer(query,
9661                                                   "SELECT proretset, prosrc, probin, "
9662                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9663                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9664                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9665                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9666                                                   "proleakproof, proconfig, procost, prorows, "
9667                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9668                                                   "FROM pg_catalog.pg_proc "
9669                                                   "WHERE oid = '%u'::pg_catalog.oid",
9670                                                   finfo->dobj.catId.oid);
9671         }
9672         else if (fout->remoteVersion >= 80400)
9673         {
9674                 /*
9675                  * In 8.4 and up we rely on pg_get_function_arguments and
9676                  * pg_get_function_result instead of examining proallargtypes etc.
9677                  */
9678                 appendPQExpBuffer(query,
9679                                                   "SELECT proretset, prosrc, probin, "
9680                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9681                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9682                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9683                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9684                                                   "false AS proleakproof, "
9685                                                   " proconfig, procost, prorows, "
9686                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9687                                                   "FROM pg_catalog.pg_proc "
9688                                                   "WHERE oid = '%u'::pg_catalog.oid",
9689                                                   finfo->dobj.catId.oid);
9690         }
9691         else if (fout->remoteVersion >= 80300)
9692         {
9693                 appendPQExpBuffer(query,
9694                                                   "SELECT proretset, prosrc, probin, "
9695                                                   "proallargtypes, proargmodes, proargnames, "
9696                                                   "false AS proiswindow, "
9697                                                   "provolatile, proisstrict, prosecdef, "
9698                                                   "false AS proleakproof, "
9699                                                   "proconfig, procost, prorows, "
9700                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9701                                                   "FROM pg_catalog.pg_proc "
9702                                                   "WHERE oid = '%u'::pg_catalog.oid",
9703                                                   finfo->dobj.catId.oid);
9704         }
9705         else if (fout->remoteVersion >= 80100)
9706         {
9707                 appendPQExpBuffer(query,
9708                                                   "SELECT proretset, prosrc, probin, "
9709                                                   "proallargtypes, proargmodes, proargnames, "
9710                                                   "false AS proiswindow, "
9711                                                   "provolatile, proisstrict, prosecdef, "
9712                                                   "false AS proleakproof, "
9713                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9714                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9715                                                   "FROM pg_catalog.pg_proc "
9716                                                   "WHERE oid = '%u'::pg_catalog.oid",
9717                                                   finfo->dobj.catId.oid);
9718         }
9719         else if (fout->remoteVersion >= 80000)
9720         {
9721                 appendPQExpBuffer(query,
9722                                                   "SELECT proretset, prosrc, probin, "
9723                                                   "null AS proallargtypes, "
9724                                                   "null AS proargmodes, "
9725                                                   "proargnames, "
9726                                                   "false AS proiswindow, "
9727                                                   "provolatile, proisstrict, prosecdef, "
9728                                                   "false AS proleakproof, "
9729                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9730                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9731                                                   "FROM pg_catalog.pg_proc "
9732                                                   "WHERE oid = '%u'::pg_catalog.oid",
9733                                                   finfo->dobj.catId.oid);
9734         }
9735         else if (fout->remoteVersion >= 70300)
9736         {
9737                 appendPQExpBuffer(query,
9738                                                   "SELECT proretset, prosrc, probin, "
9739                                                   "null AS proallargtypes, "
9740                                                   "null AS proargmodes, "
9741                                                   "null AS proargnames, "
9742                                                   "false AS proiswindow, "
9743                                                   "provolatile, proisstrict, prosecdef, "
9744                                                   "false AS proleakproof, "
9745                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9746                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9747                                                   "FROM pg_catalog.pg_proc "
9748                                                   "WHERE oid = '%u'::pg_catalog.oid",
9749                                                   finfo->dobj.catId.oid);
9750         }
9751         else if (fout->remoteVersion >= 70100)
9752         {
9753                 appendPQExpBuffer(query,
9754                                                   "SELECT proretset, prosrc, probin, "
9755                                                   "null AS proallargtypes, "
9756                                                   "null AS proargmodes, "
9757                                                   "null AS proargnames, "
9758                                                   "false AS proiswindow, "
9759                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9760                                                   "proisstrict, "
9761                                                   "false AS prosecdef, "
9762                                                   "false AS proleakproof, "
9763                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9764                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9765                                                   "FROM pg_proc "
9766                                                   "WHERE oid = '%u'::oid",
9767                                                   finfo->dobj.catId.oid);
9768         }
9769         else
9770         {
9771                 appendPQExpBuffer(query,
9772                                                   "SELECT proretset, prosrc, probin, "
9773                                                   "null AS proallargtypes, "
9774                                                   "null AS proargmodes, "
9775                                                   "null AS proargnames, "
9776                                                   "false AS proiswindow, "
9777                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9778                                                   "false AS proisstrict, "
9779                                                   "false AS prosecdef, "
9780                                                   "false AS proleakproof, "
9781                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9782                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9783                                                   "FROM pg_proc "
9784                                                   "WHERE oid = '%u'::oid",
9785                                                   finfo->dobj.catId.oid);
9786         }
9787
9788         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9789
9790         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9791         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9792         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9793         if (fout->remoteVersion >= 80400)
9794         {
9795                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9796                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9797                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9798                 proallargtypes = proargmodes = proargnames = NULL;
9799         }
9800         else
9801         {
9802                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9803                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9804                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9805                 funcargs = funciargs = funcresult = NULL;
9806         }
9807         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9808         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9809         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9810         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9811         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9812         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9813         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9814         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9815         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9816
9817         /*
9818          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9819          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9820          * versions would set it to "-".  There are no known cases in which prosrc
9821          * is unused, so the tests below for "-" are probably useless.
9822          */
9823         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9824         {
9825                 appendPQExpBuffer(asPart, "AS ");
9826                 appendStringLiteralAH(asPart, probin, fout);
9827                 if (strcmp(prosrc, "-") != 0)
9828                 {
9829                         appendPQExpBuffer(asPart, ", ");
9830
9831                         /*
9832                          * where we have bin, use dollar quoting if allowed and src
9833                          * contains quote or backslash; else use regular quoting.
9834                          */
9835                         if (disable_dollar_quoting ||
9836                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9837                                 appendStringLiteralAH(asPart, prosrc, fout);
9838                         else
9839                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9840                 }
9841         }
9842         else
9843         {
9844                 if (strcmp(prosrc, "-") != 0)
9845                 {
9846                         appendPQExpBuffer(asPart, "AS ");
9847                         /* with no bin, dollar quote src unconditionally if allowed */
9848                         if (disable_dollar_quoting)
9849                                 appendStringLiteralAH(asPart, prosrc, fout);
9850                         else
9851                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9852                 }
9853         }
9854
9855         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9856
9857         if (proallargtypes && *proallargtypes)
9858         {
9859                 int                     nitems = 0;
9860
9861                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9862                         nitems < finfo->nargs)
9863                 {
9864                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9865                         if (allargtypes)
9866                                 free(allargtypes);
9867                         allargtypes = NULL;
9868                 }
9869                 else
9870                         nallargs = nitems;
9871         }
9872
9873         if (proargmodes && *proargmodes)
9874         {
9875                 int                     nitems = 0;
9876
9877                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9878                         nitems != nallargs)
9879                 {
9880                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9881                         if (argmodes)
9882                                 free(argmodes);
9883                         argmodes = NULL;
9884                 }
9885         }
9886
9887         if (proargnames && *proargnames)
9888         {
9889                 int                     nitems = 0;
9890
9891                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9892                         nitems != nallargs)
9893                 {
9894                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9895                         if (argnames)
9896                                 free(argnames);
9897                         argnames = NULL;
9898                 }
9899         }
9900
9901         if (proconfig && *proconfig)
9902         {
9903                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9904                 {
9905                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9906                         if (configitems)
9907                                 free(configitems);
9908                         configitems = NULL;
9909                         nconfigitems = 0;
9910                 }
9911         }
9912
9913         if (funcargs)
9914         {
9915                 /* 8.4 or later; we rely on server-side code for most of the work */
9916                 funcfullsig = format_function_arguments(finfo, funcargs, false);
9917                 funcsig = format_function_arguments(finfo, funciargs, false);
9918         }
9919         else
9920         {
9921                 /* pre-8.4, do it ourselves */
9922                 funcsig = format_function_arguments_old(fout,
9923                                                                                                 finfo, nallargs, allargtypes,
9924                                                                                                 argmodes, argnames);
9925                 funcfullsig = funcsig;
9926         }
9927
9928         funcsig_tag = format_function_signature(fout, finfo, false);
9929
9930         /*
9931          * DROP must be fully qualified in case same name appears in pg_catalog
9932          */
9933         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9934                                           fmtId(finfo->dobj.namespace->dobj.name),
9935                                           funcsig);
9936
9937         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9938         if (funcresult)
9939                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9940         else
9941         {
9942                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9943                                                                                    zeroAsOpaque);
9944                 appendPQExpBuffer(q, "RETURNS %s%s",
9945                                                   (proretset[0] == 't') ? "SETOF " : "",
9946                                                   rettypename);
9947                 free(rettypename);
9948         }
9949
9950         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9951
9952         if (proiswindow[0] == 't')
9953                 appendPQExpBuffer(q, " WINDOW");
9954
9955         if (provolatile[0] != PROVOLATILE_VOLATILE)
9956         {
9957                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9958                         appendPQExpBuffer(q, " IMMUTABLE");
9959                 else if (provolatile[0] == PROVOLATILE_STABLE)
9960                         appendPQExpBuffer(q, " STABLE");
9961                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9962                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9963                                                   finfo->dobj.name);
9964         }
9965
9966         if (proisstrict[0] == 't')
9967                 appendPQExpBuffer(q, " STRICT");
9968
9969         if (prosecdef[0] == 't')
9970                 appendPQExpBuffer(q, " SECURITY DEFINER");
9971
9972         if (proleakproof[0] == 't')
9973                 appendPQExpBuffer(q, " LEAKPROOF");
9974
9975         /*
9976          * COST and ROWS are emitted only if present and not default, so as not to
9977          * break backwards-compatibility of the dump without need.      Keep this code
9978          * in sync with the defaults in functioncmds.c.
9979          */
9980         if (strcmp(procost, "0") != 0)
9981         {
9982                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9983                 {
9984                         /* default cost is 1 */
9985                         if (strcmp(procost, "1") != 0)
9986                                 appendPQExpBuffer(q, " COST %s", procost);
9987                 }
9988                 else
9989                 {
9990                         /* default cost is 100 */
9991                         if (strcmp(procost, "100") != 0)
9992                                 appendPQExpBuffer(q, " COST %s", procost);
9993                 }
9994         }
9995         if (proretset[0] == 't' &&
9996                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9997                 appendPQExpBuffer(q, " ROWS %s", prorows);
9998
9999         for (i = 0; i < nconfigitems; i++)
10000         {
10001                 /* we feel free to scribble on configitems[] here */
10002                 char       *configitem = configitems[i];
10003                 char       *pos;
10004
10005                 pos = strchr(configitem, '=');
10006                 if (pos == NULL)
10007                         continue;
10008                 *pos++ = '\0';
10009                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
10010
10011                 /*
10012                  * Some GUC variable names are 'LIST' type and hence must not be
10013                  * quoted.
10014                  */
10015                 if (pg_strcasecmp(configitem, "DateStyle") == 0
10016                         || pg_strcasecmp(configitem, "search_path") == 0)
10017                         appendPQExpBuffer(q, "%s", pos);
10018                 else
10019                         appendStringLiteralAH(q, pos, fout);
10020         }
10021
10022         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
10023
10024         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
10025
10026         if (binary_upgrade)
10027                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
10028
10029         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
10030                                  funcsig_tag,
10031                                  finfo->dobj.namespace->dobj.name,
10032                                  NULL,
10033                                  finfo->rolname, false,
10034                                  "FUNCTION", SECTION_PRE_DATA,
10035                                  q->data, delqry->data, NULL,
10036                                  NULL, 0,
10037                                  NULL, NULL);
10038
10039         /* Dump Function Comments and Security Labels */
10040         dumpComment(fout, labelq->data,
10041                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
10042                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
10043         dumpSecLabel(fout, labelq->data,
10044                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
10045                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
10046
10047         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
10048                         funcsig, NULL, funcsig_tag,
10049                         finfo->dobj.namespace->dobj.name,
10050                         finfo->rolname, finfo->proacl);
10051
10052         PQclear(res);
10053
10054         destroyPQExpBuffer(query);
10055         destroyPQExpBuffer(q);
10056         destroyPQExpBuffer(delqry);
10057         destroyPQExpBuffer(labelq);
10058         destroyPQExpBuffer(asPart);
10059         free(funcsig);
10060         free(funcsig_tag);
10061         if (allargtypes)
10062                 free(allargtypes);
10063         if (argmodes)
10064                 free(argmodes);
10065         if (argnames)
10066                 free(argnames);
10067         if (configitems)
10068                 free(configitems);
10069 }
10070
10071
10072 /*
10073  * Dump a user-defined cast
10074  */
10075 static void
10076 dumpCast(Archive *fout, CastInfo *cast)
10077 {
10078         PQExpBuffer defqry;
10079         PQExpBuffer delqry;
10080         PQExpBuffer labelq;
10081         FuncInfo   *funcInfo = NULL;
10082
10083         /* Skip if not to be dumped */
10084         if (!cast->dobj.dump || dataOnly)
10085                 return;
10086
10087         /* Cannot dump if we don't have the cast function's info */
10088         if (OidIsValid(cast->castfunc))
10089         {
10090                 funcInfo = findFuncByOid(cast->castfunc);
10091                 if (funcInfo == NULL)
10092                         return;
10093         }
10094
10095         /*
10096          * As per discussion we dump casts if one or more of the underlying
10097          * objects (the conversion function and the two data types) are not
10098          * builtin AND if all of the non-builtin objects are included in the dump.
10099          * Builtin meaning, the namespace name does not start with "pg_".
10100          *
10101          * However, for a cast that belongs to an extension, we must not use this
10102          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
10103          */
10104         if (!cast->dobj.ext_member)
10105         {
10106                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
10107                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
10108
10109                 if (sourceInfo == NULL || targetInfo == NULL)
10110                         return;
10111
10112                 /*
10113                  * Skip this cast if all objects are from pg_
10114                  */
10115                 if ((funcInfo == NULL ||
10116                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
10117                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10118                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10119                         return;
10120
10121                 /*
10122                  * Skip cast if function isn't from pg_ and is not to be dumped.
10123                  */
10124                 if (funcInfo &&
10125                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10126                         !funcInfo->dobj.dump)
10127                         return;
10128
10129                 /*
10130                  * Same for the source type
10131                  */
10132                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10133                         !sourceInfo->dobj.dump)
10134                         return;
10135
10136                 /*
10137                  * and the target type.
10138                  */
10139                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10140                         !targetInfo->dobj.dump)
10141                         return;
10142         }
10143
10144         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10145         selectSourceSchema(fout, "pg_catalog");
10146
10147         defqry = createPQExpBuffer();
10148         delqry = createPQExpBuffer();
10149         labelq = createPQExpBuffer();
10150
10151         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10152                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10153                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10154
10155         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10156                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10157                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10158
10159         switch (cast->castmethod)
10160         {
10161                 case COERCION_METHOD_BINARY:
10162                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
10163                         break;
10164                 case COERCION_METHOD_INOUT:
10165                         appendPQExpBuffer(defqry, "WITH INOUT");
10166                         break;
10167                 case COERCION_METHOD_FUNCTION:
10168                         if (funcInfo)
10169                         {
10170                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10171
10172                                 /*
10173                                  * Always qualify the function name, in case it is not in
10174                                  * pg_catalog schema (format_function_signature won't qualify
10175                                  * it).
10176                                  */
10177                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10178                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10179                                 free(fsig);
10180                         }
10181                         else
10182                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10183                         break;
10184                 default:
10185                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10186         }
10187
10188         if (cast->castcontext == 'a')
10189                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
10190         else if (cast->castcontext == 'i')
10191                 appendPQExpBuffer(defqry, " AS IMPLICIT");
10192         appendPQExpBuffer(defqry, ";\n");
10193
10194         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10195                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10196                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10197
10198         if (binary_upgrade)
10199                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10200
10201         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10202                                  labelq->data,
10203                                  "pg_catalog", NULL, "",
10204                                  false, "CAST", SECTION_PRE_DATA,
10205                                  defqry->data, delqry->data, NULL,
10206                                  NULL, 0,
10207                                  NULL, NULL);
10208
10209         /* Dump Cast Comments */
10210         dumpComment(fout, labelq->data,
10211                                 NULL, "",
10212                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10213
10214         destroyPQExpBuffer(defqry);
10215         destroyPQExpBuffer(delqry);
10216         destroyPQExpBuffer(labelq);
10217 }
10218
10219 /*
10220  * dumpOpr
10221  *        write out a single operator definition
10222  */
10223 static void
10224 dumpOpr(Archive *fout, OprInfo *oprinfo)
10225 {
10226         PQExpBuffer query;
10227         PQExpBuffer q;
10228         PQExpBuffer delq;
10229         PQExpBuffer labelq;
10230         PQExpBuffer oprid;
10231         PQExpBuffer details;
10232         const char *name;
10233         PGresult   *res;
10234         int                     i_oprkind;
10235         int                     i_oprcode;
10236         int                     i_oprleft;
10237         int                     i_oprright;
10238         int                     i_oprcom;
10239         int                     i_oprnegate;
10240         int                     i_oprrest;
10241         int                     i_oprjoin;
10242         int                     i_oprcanmerge;
10243         int                     i_oprcanhash;
10244         char       *oprkind;
10245         char       *oprcode;
10246         char       *oprleft;
10247         char       *oprright;
10248         char       *oprcom;
10249         char       *oprnegate;
10250         char       *oprrest;
10251         char       *oprjoin;
10252         char       *oprcanmerge;
10253         char       *oprcanhash;
10254
10255         /* Skip if not to be dumped */
10256         if (!oprinfo->dobj.dump || dataOnly)
10257                 return;
10258
10259         /*
10260          * some operators are invalid because they were the result of user
10261          * defining operators before commutators exist
10262          */
10263         if (!OidIsValid(oprinfo->oprcode))
10264                 return;
10265
10266         query = createPQExpBuffer();
10267         q = createPQExpBuffer();
10268         delq = createPQExpBuffer();
10269         labelq = createPQExpBuffer();
10270         oprid = createPQExpBuffer();
10271         details = createPQExpBuffer();
10272
10273         /* Make sure we are in proper schema so regoperator works correctly */
10274         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10275
10276         if (fout->remoteVersion >= 80300)
10277         {
10278                 appendPQExpBuffer(query, "SELECT oprkind, "
10279                                                   "oprcode::pg_catalog.regprocedure, "
10280                                                   "oprleft::pg_catalog.regtype, "
10281                                                   "oprright::pg_catalog.regtype, "
10282                                                   "oprcom::pg_catalog.regoperator, "
10283                                                   "oprnegate::pg_catalog.regoperator, "
10284                                                   "oprrest::pg_catalog.regprocedure, "
10285                                                   "oprjoin::pg_catalog.regprocedure, "
10286                                                   "oprcanmerge, oprcanhash "
10287                                                   "FROM pg_catalog.pg_operator "
10288                                                   "WHERE oid = '%u'::pg_catalog.oid",
10289                                                   oprinfo->dobj.catId.oid);
10290         }
10291         else if (fout->remoteVersion >= 70300)
10292         {
10293                 appendPQExpBuffer(query, "SELECT oprkind, "
10294                                                   "oprcode::pg_catalog.regprocedure, "
10295                                                   "oprleft::pg_catalog.regtype, "
10296                                                   "oprright::pg_catalog.regtype, "
10297                                                   "oprcom::pg_catalog.regoperator, "
10298                                                   "oprnegate::pg_catalog.regoperator, "
10299                                                   "oprrest::pg_catalog.regprocedure, "
10300                                                   "oprjoin::pg_catalog.regprocedure, "
10301                                                   "(oprlsortop != 0) AS oprcanmerge, "
10302                                                   "oprcanhash "
10303                                                   "FROM pg_catalog.pg_operator "
10304                                                   "WHERE oid = '%u'::pg_catalog.oid",
10305                                                   oprinfo->dobj.catId.oid);
10306         }
10307         else if (fout->remoteVersion >= 70100)
10308         {
10309                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10310                                                   "CASE WHEN oprleft = 0 THEN '-' "
10311                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10312                                                   "CASE WHEN oprright = 0 THEN '-' "
10313                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10314                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10315                                                   "(oprlsortop != 0) AS oprcanmerge, "
10316                                                   "oprcanhash "
10317                                                   "FROM pg_operator "
10318                                                   "WHERE oid = '%u'::oid",
10319                                                   oprinfo->dobj.catId.oid);
10320         }
10321         else
10322         {
10323                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10324                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10325                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10326                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10327                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10328                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10329                                                   "(oprlsortop != 0) AS oprcanmerge, "
10330                                                   "oprcanhash "
10331                                                   "FROM pg_operator "
10332                                                   "WHERE oid = '%u'::oid",
10333                                                   oprinfo->dobj.catId.oid);
10334         }
10335
10336         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10337
10338         i_oprkind = PQfnumber(res, "oprkind");
10339         i_oprcode = PQfnumber(res, "oprcode");
10340         i_oprleft = PQfnumber(res, "oprleft");
10341         i_oprright = PQfnumber(res, "oprright");
10342         i_oprcom = PQfnumber(res, "oprcom");
10343         i_oprnegate = PQfnumber(res, "oprnegate");
10344         i_oprrest = PQfnumber(res, "oprrest");
10345         i_oprjoin = PQfnumber(res, "oprjoin");
10346         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10347         i_oprcanhash = PQfnumber(res, "oprcanhash");
10348
10349         oprkind = PQgetvalue(res, 0, i_oprkind);
10350         oprcode = PQgetvalue(res, 0, i_oprcode);
10351         oprleft = PQgetvalue(res, 0, i_oprleft);
10352         oprright = PQgetvalue(res, 0, i_oprright);
10353         oprcom = PQgetvalue(res, 0, i_oprcom);
10354         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10355         oprrest = PQgetvalue(res, 0, i_oprrest);
10356         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10357         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10358         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10359
10360         appendPQExpBuffer(details, "    PROCEDURE = %s",
10361                                           convertRegProcReference(fout, oprcode));
10362
10363         appendPQExpBuffer(oprid, "%s (",
10364                                           oprinfo->dobj.name);
10365
10366         /*
10367          * right unary means there's a left arg and left unary means there's a
10368          * right arg
10369          */
10370         if (strcmp(oprkind, "r") == 0 ||
10371                 strcmp(oprkind, "b") == 0)
10372         {
10373                 if (fout->remoteVersion >= 70100)
10374                         name = oprleft;
10375                 else
10376                         name = fmtId(oprleft);
10377                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10378                 appendPQExpBuffer(oprid, "%s", name);
10379         }
10380         else
10381                 appendPQExpBuffer(oprid, "NONE");
10382
10383         if (strcmp(oprkind, "l") == 0 ||
10384                 strcmp(oprkind, "b") == 0)
10385         {
10386                 if (fout->remoteVersion >= 70100)
10387                         name = oprright;
10388                 else
10389                         name = fmtId(oprright);
10390                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10391                 appendPQExpBuffer(oprid, ", %s)", name);
10392         }
10393         else
10394                 appendPQExpBuffer(oprid, ", NONE)");
10395
10396         name = convertOperatorReference(fout, oprcom);
10397         if (name)
10398                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
10399
10400         name = convertOperatorReference(fout, oprnegate);
10401         if (name)
10402                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
10403
10404         if (strcmp(oprcanmerge, "t") == 0)
10405                 appendPQExpBuffer(details, ",\n    MERGES");
10406
10407         if (strcmp(oprcanhash, "t") == 0)
10408                 appendPQExpBuffer(details, ",\n    HASHES");
10409
10410         name = convertRegProcReference(fout, oprrest);
10411         if (name)
10412                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
10413
10414         name = convertRegProcReference(fout, oprjoin);
10415         if (name)
10416                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
10417
10418         /*
10419          * DROP must be fully qualified in case same name appears in pg_catalog
10420          */
10421         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10422                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10423                                           oprid->data);
10424
10425         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10426                                           oprinfo->dobj.name, details->data);
10427
10428         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10429
10430         if (binary_upgrade)
10431                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10432
10433         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10434                                  oprinfo->dobj.name,
10435                                  oprinfo->dobj.namespace->dobj.name,
10436                                  NULL,
10437                                  oprinfo->rolname,
10438                                  false, "OPERATOR", SECTION_PRE_DATA,
10439                                  q->data, delq->data, NULL,
10440                                  NULL, 0,
10441                                  NULL, NULL);
10442
10443         /* Dump Operator Comments */
10444         dumpComment(fout, labelq->data,
10445                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10446                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10447
10448         PQclear(res);
10449
10450         destroyPQExpBuffer(query);
10451         destroyPQExpBuffer(q);
10452         destroyPQExpBuffer(delq);
10453         destroyPQExpBuffer(labelq);
10454         destroyPQExpBuffer(oprid);
10455         destroyPQExpBuffer(details);
10456 }
10457
10458 /*
10459  * Convert a function reference obtained from pg_operator
10460  *
10461  * Returns what to print, or NULL if function references is InvalidOid
10462  *
10463  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10464  * argument-types part.  In prior versions, the input is a REGPROC display.
10465  */
10466 static const char *
10467 convertRegProcReference(Archive *fout, const char *proc)
10468 {
10469         /* In all cases "-" means a null reference */
10470         if (strcmp(proc, "-") == 0)
10471                 return NULL;
10472
10473         if (fout->remoteVersion >= 70300)
10474         {
10475                 char       *name;
10476                 char       *paren;
10477                 bool            inquote;
10478
10479                 name = pg_strdup(proc);
10480                 /* find non-double-quoted left paren */
10481                 inquote = false;
10482                 for (paren = name; *paren; paren++)
10483                 {
10484                         if (*paren == '(' && !inquote)
10485                         {
10486                                 *paren = '\0';
10487                                 break;
10488                         }
10489                         if (*paren == '"')
10490                                 inquote = !inquote;
10491                 }
10492                 return name;
10493         }
10494
10495         /* REGPROC before 7.3 does not quote its result */
10496         return fmtId(proc);
10497 }
10498
10499 /*
10500  * Convert an operator cross-reference obtained from pg_operator
10501  *
10502  * Returns what to print, or NULL to print nothing
10503  *
10504  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10505  * argument-types part, and add OPERATOR() decoration if the name is
10506  * schema-qualified.  In older versions, the input is just a numeric OID,
10507  * which we search our operator list for.
10508  */
10509 static const char *
10510 convertOperatorReference(Archive *fout, const char *opr)
10511 {
10512         OprInfo    *oprInfo;
10513
10514         /* In all cases "0" means a null reference */
10515         if (strcmp(opr, "0") == 0)
10516                 return NULL;
10517
10518         if (fout->remoteVersion >= 70300)
10519         {
10520                 char       *name;
10521                 char       *oname;
10522                 char       *ptr;
10523                 bool            inquote;
10524                 bool            sawdot;
10525
10526                 name = pg_strdup(opr);
10527                 /* find non-double-quoted left paren, and check for non-quoted dot */
10528                 inquote = false;
10529                 sawdot = false;
10530                 for (ptr = name; *ptr; ptr++)
10531                 {
10532                         if (*ptr == '"')
10533                                 inquote = !inquote;
10534                         else if (*ptr == '.' && !inquote)
10535                                 sawdot = true;
10536                         else if (*ptr == '(' && !inquote)
10537                         {
10538                                 *ptr = '\0';
10539                                 break;
10540                         }
10541                 }
10542                 /* If not schema-qualified, don't need to add OPERATOR() */
10543                 if (!sawdot)
10544                         return name;
10545                 oname = psprintf("OPERATOR(%s)", name);
10546                 free(name);
10547                 return oname;
10548         }
10549
10550         oprInfo = findOprByOid(atooid(opr));
10551         if (oprInfo == NULL)
10552         {
10553                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10554                                   opr);
10555                 return NULL;
10556         }
10557         return oprInfo->dobj.name;
10558 }
10559
10560 /*
10561  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10562  *
10563  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10564  * argument lists of these functions are predetermined.  Note that the
10565  * caller should ensure we are in the proper schema, because the results
10566  * are search path dependent!
10567  */
10568 static const char *
10569 convertTSFunction(Archive *fout, Oid funcOid)
10570 {
10571         char       *result;
10572         char            query[128];
10573         PGresult   *res;
10574
10575         snprintf(query, sizeof(query),
10576                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10577         res = ExecuteSqlQueryForSingleRow(fout, query);
10578
10579         result = pg_strdup(PQgetvalue(res, 0, 0));
10580
10581         PQclear(res);
10582
10583         return result;
10584 }
10585
10586
10587 /*
10588  * dumpOpclass
10589  *        write out a single operator class definition
10590  */
10591 static void
10592 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10593 {
10594         PQExpBuffer query;
10595         PQExpBuffer q;
10596         PQExpBuffer delq;
10597         PQExpBuffer labelq;
10598         PGresult   *res;
10599         int                     ntups;
10600         int                     i_opcintype;
10601         int                     i_opckeytype;
10602         int                     i_opcdefault;
10603         int                     i_opcfamily;
10604         int                     i_opcfamilyname;
10605         int                     i_opcfamilynsp;
10606         int                     i_amname;
10607         int                     i_amopstrategy;
10608         int                     i_amopreqcheck;
10609         int                     i_amopopr;
10610         int                     i_sortfamily;
10611         int                     i_sortfamilynsp;
10612         int                     i_amprocnum;
10613         int                     i_amproc;
10614         int                     i_amproclefttype;
10615         int                     i_amprocrighttype;
10616         char       *opcintype;
10617         char       *opckeytype;
10618         char       *opcdefault;
10619         char       *opcfamily;
10620         char       *opcfamilyname;
10621         char       *opcfamilynsp;
10622         char       *amname;
10623         char       *amopstrategy;
10624         char       *amopreqcheck;
10625         char       *amopopr;
10626         char       *sortfamily;
10627         char       *sortfamilynsp;
10628         char       *amprocnum;
10629         char       *amproc;
10630         char       *amproclefttype;
10631         char       *amprocrighttype;
10632         bool            needComma;
10633         int                     i;
10634
10635         /* Skip if not to be dumped */
10636         if (!opcinfo->dobj.dump || dataOnly)
10637                 return;
10638
10639         /*
10640          * XXX currently we do not implement dumping of operator classes from
10641          * pre-7.3 databases.  This could be done but it seems not worth the
10642          * trouble.
10643          */
10644         if (fout->remoteVersion < 70300)
10645                 return;
10646
10647         query = createPQExpBuffer();
10648         q = createPQExpBuffer();
10649         delq = createPQExpBuffer();
10650         labelq = createPQExpBuffer();
10651
10652         /* Make sure we are in proper schema so regoperator works correctly */
10653         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10654
10655         /* Get additional fields from the pg_opclass row */
10656         if (fout->remoteVersion >= 80300)
10657         {
10658                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10659                                                   "opckeytype::pg_catalog.regtype, "
10660                                                   "opcdefault, opcfamily, "
10661                                                   "opfname AS opcfamilyname, "
10662                                                   "nspname AS opcfamilynsp, "
10663                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10664                                                   "FROM pg_catalog.pg_opclass c "
10665                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10666                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10667                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10668                                                   opcinfo->dobj.catId.oid);
10669         }
10670         else
10671         {
10672                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10673                                                   "opckeytype::pg_catalog.regtype, "
10674                                                   "opcdefault, NULL AS opcfamily, "
10675                                                   "NULL AS opcfamilyname, "
10676                                                   "NULL AS opcfamilynsp, "
10677                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10678                                                   "FROM pg_catalog.pg_opclass "
10679                                                   "WHERE oid = '%u'::pg_catalog.oid",
10680                                                   opcinfo->dobj.catId.oid);
10681         }
10682
10683         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10684
10685         i_opcintype = PQfnumber(res, "opcintype");
10686         i_opckeytype = PQfnumber(res, "opckeytype");
10687         i_opcdefault = PQfnumber(res, "opcdefault");
10688         i_opcfamily = PQfnumber(res, "opcfamily");
10689         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10690         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10691         i_amname = PQfnumber(res, "amname");
10692
10693         opcintype = PQgetvalue(res, 0, i_opcintype);
10694         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10695         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10696         /* opcfamily will still be needed after we PQclear res */
10697         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10698         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10699         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10700         /* amname will still be needed after we PQclear res */
10701         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10702
10703         /*
10704          * DROP must be fully qualified in case same name appears in pg_catalog
10705          */
10706         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10707                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10708         appendPQExpBuffer(delq, ".%s",
10709                                           fmtId(opcinfo->dobj.name));
10710         appendPQExpBuffer(delq, " USING %s;\n",
10711                                           fmtId(amname));
10712
10713         /* Build the fixed portion of the CREATE command */
10714         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10715                                           fmtId(opcinfo->dobj.name));
10716         if (strcmp(opcdefault, "t") == 0)
10717                 appendPQExpBuffer(q, "DEFAULT ");
10718         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10719                                           opcintype,
10720                                           fmtId(amname));
10721         if (strlen(opcfamilyname) > 0 &&
10722                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10723                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10724         {
10725                 appendPQExpBuffer(q, " FAMILY ");
10726                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10727                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10728                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10729         }
10730         appendPQExpBuffer(q, " AS\n    ");
10731
10732         needComma = false;
10733
10734         if (strcmp(opckeytype, "-") != 0)
10735         {
10736                 appendPQExpBuffer(q, "STORAGE %s",
10737                                                   opckeytype);
10738                 needComma = true;
10739         }
10740
10741         PQclear(res);
10742
10743         /*
10744          * Now fetch and print the OPERATOR entries (pg_amop rows).
10745          *
10746          * Print only those opfamily members that are tied to the opclass by
10747          * pg_depend entries.
10748          *
10749          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10750          * older server's opclass in which it is used.  This is to avoid
10751          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10752          * older server and then reload into that old version.  This can go away
10753          * once 8.3 is so old as to not be of interest to anyone.
10754          */
10755         resetPQExpBuffer(query);
10756
10757         if (fout->remoteVersion >= 90100)
10758         {
10759                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10760                                                   "amopopr::pg_catalog.regoperator, "
10761                                                   "opfname AS sortfamily, "
10762                                                   "nspname AS sortfamilynsp "
10763                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10764                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10765                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10766                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10767                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10768                                                   "AND refobjid = '%u'::pg_catalog.oid "
10769                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10770                                                   "ORDER BY amopstrategy",
10771                                                   opcinfo->dobj.catId.oid,
10772                                                   opcfamily);
10773         }
10774         else if (fout->remoteVersion >= 80400)
10775         {
10776                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10777                                                   "amopopr::pg_catalog.regoperator, "
10778                                                   "NULL AS sortfamily, "
10779                                                   "NULL AS sortfamilynsp "
10780                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10781                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10782                                                   "AND refobjid = '%u'::pg_catalog.oid "
10783                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10784                                                   "AND objid = ao.oid "
10785                                                   "ORDER BY amopstrategy",
10786                                                   opcinfo->dobj.catId.oid);
10787         }
10788         else if (fout->remoteVersion >= 80300)
10789         {
10790                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10791                                                   "amopopr::pg_catalog.regoperator, "
10792                                                   "NULL AS sortfamily, "
10793                                                   "NULL AS sortfamilynsp "
10794                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10795                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10796                                                   "AND refobjid = '%u'::pg_catalog.oid "
10797                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10798                                                   "AND objid = ao.oid "
10799                                                   "ORDER BY amopstrategy",
10800                                                   opcinfo->dobj.catId.oid);
10801         }
10802         else
10803         {
10804                 /*
10805                  * Here, we print all entries since there are no opfamilies and hence
10806                  * no loose operators to worry about.
10807                  */
10808                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10809                                                   "amopopr::pg_catalog.regoperator, "
10810                                                   "NULL AS sortfamily, "
10811                                                   "NULL AS sortfamilynsp "
10812                                                   "FROM pg_catalog.pg_amop "
10813                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10814                                                   "ORDER BY amopstrategy",
10815                                                   opcinfo->dobj.catId.oid);
10816         }
10817
10818         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10819
10820         ntups = PQntuples(res);
10821
10822         i_amopstrategy = PQfnumber(res, "amopstrategy");
10823         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10824         i_amopopr = PQfnumber(res, "amopopr");
10825         i_sortfamily = PQfnumber(res, "sortfamily");
10826         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10827
10828         for (i = 0; i < ntups; i++)
10829         {
10830                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10831                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10832                 amopopr = PQgetvalue(res, i, i_amopopr);
10833                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10834                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10835
10836                 if (needComma)
10837                         appendPQExpBuffer(q, " ,\n    ");
10838
10839                 appendPQExpBuffer(q, "OPERATOR %s %s",
10840                                                   amopstrategy, amopopr);
10841
10842                 if (strlen(sortfamily) > 0)
10843                 {
10844                         appendPQExpBuffer(q, " FOR ORDER BY ");
10845                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10846                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10847                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10848                 }
10849
10850                 if (strcmp(amopreqcheck, "t") == 0)
10851                         appendPQExpBuffer(q, " RECHECK");
10852
10853                 needComma = true;
10854         }
10855
10856         PQclear(res);
10857
10858         /*
10859          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10860          *
10861          * Print only those opfamily members that are tied to the opclass by
10862          * pg_depend entries.
10863          *
10864          * We print the amproclefttype/amprocrighttype even though in most cases
10865          * the backend could deduce the right values, because of the corner case
10866          * of a btree sort support function for a cross-type comparison.  That's
10867          * only allowed in 9.2 and later, but for simplicity print them in all
10868          * versions that have the columns.
10869          */
10870         resetPQExpBuffer(query);
10871
10872         if (fout->remoteVersion >= 80300)
10873         {
10874                 appendPQExpBuffer(query, "SELECT amprocnum, "
10875                                                   "amproc::pg_catalog.regprocedure, "
10876                                                   "amproclefttype::pg_catalog.regtype, "
10877                                                   "amprocrighttype::pg_catalog.regtype "
10878                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10879                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10880                                                   "AND refobjid = '%u'::pg_catalog.oid "
10881                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10882                                                   "AND objid = ap.oid "
10883                                                   "ORDER BY amprocnum",
10884                                                   opcinfo->dobj.catId.oid);
10885         }
10886         else
10887         {
10888                 appendPQExpBuffer(query, "SELECT amprocnum, "
10889                                                   "amproc::pg_catalog.regprocedure, "
10890                                                   "'' AS amproclefttype, "
10891                                                   "'' AS amprocrighttype "
10892                                                   "FROM pg_catalog.pg_amproc "
10893                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10894                                                   "ORDER BY amprocnum",
10895                                                   opcinfo->dobj.catId.oid);
10896         }
10897
10898         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10899
10900         ntups = PQntuples(res);
10901
10902         i_amprocnum = PQfnumber(res, "amprocnum");
10903         i_amproc = PQfnumber(res, "amproc");
10904         i_amproclefttype = PQfnumber(res, "amproclefttype");
10905         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10906
10907         for (i = 0; i < ntups; i++)
10908         {
10909                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10910                 amproc = PQgetvalue(res, i, i_amproc);
10911                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10912                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10913
10914                 if (needComma)
10915                         appendPQExpBuffer(q, " ,\n    ");
10916
10917                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10918
10919                 if (*amproclefttype && *amprocrighttype)
10920                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10921
10922                 appendPQExpBuffer(q, " %s", amproc);
10923
10924                 needComma = true;
10925         }
10926
10927         PQclear(res);
10928
10929         appendPQExpBuffer(q, ";\n");
10930
10931         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10932                                           fmtId(opcinfo->dobj.name));
10933         appendPQExpBuffer(labelq, " USING %s",
10934                                           fmtId(amname));
10935
10936         if (binary_upgrade)
10937                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10938
10939         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10940                                  opcinfo->dobj.name,
10941                                  opcinfo->dobj.namespace->dobj.name,
10942                                  NULL,
10943                                  opcinfo->rolname,
10944                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10945                                  q->data, delq->data, NULL,
10946                                  NULL, 0,
10947                                  NULL, NULL);
10948
10949         /* Dump Operator Class Comments */
10950         dumpComment(fout, labelq->data,
10951                                 NULL, opcinfo->rolname,
10952                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10953
10954         free(amname);
10955         destroyPQExpBuffer(query);
10956         destroyPQExpBuffer(q);
10957         destroyPQExpBuffer(delq);
10958         destroyPQExpBuffer(labelq);
10959 }
10960
10961 /*
10962  * dumpOpfamily
10963  *        write out a single operator family definition
10964  *
10965  * Note: this also dumps any "loose" operator members that aren't bound to a
10966  * specific opclass within the opfamily.
10967  */
10968 static void
10969 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10970 {
10971         PQExpBuffer query;
10972         PQExpBuffer q;
10973         PQExpBuffer delq;
10974         PQExpBuffer labelq;
10975         PGresult   *res;
10976         PGresult   *res_ops;
10977         PGresult   *res_procs;
10978         int                     ntups;
10979         int                     i_amname;
10980         int                     i_amopstrategy;
10981         int                     i_amopreqcheck;
10982         int                     i_amopopr;
10983         int                     i_sortfamily;
10984         int                     i_sortfamilynsp;
10985         int                     i_amprocnum;
10986         int                     i_amproc;
10987         int                     i_amproclefttype;
10988         int                     i_amprocrighttype;
10989         char       *amname;
10990         char       *amopstrategy;
10991         char       *amopreqcheck;
10992         char       *amopopr;
10993         char       *sortfamily;
10994         char       *sortfamilynsp;
10995         char       *amprocnum;
10996         char       *amproc;
10997         char       *amproclefttype;
10998         char       *amprocrighttype;
10999         bool            needComma;
11000         int                     i;
11001
11002         /* Skip if not to be dumped */
11003         if (!opfinfo->dobj.dump || dataOnly)
11004                 return;
11005
11006         /*
11007          * We want to dump the opfamily only if (1) it contains "loose" operators
11008          * or functions, or (2) it contains an opclass with a different name or
11009          * owner.  Otherwise it's sufficient to let it be created during creation
11010          * of the contained opclass, and not dumping it improves portability of
11011          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
11012          * that first.
11013          */
11014
11015         query = createPQExpBuffer();
11016         q = createPQExpBuffer();
11017         delq = createPQExpBuffer();
11018         labelq = createPQExpBuffer();
11019
11020         /* Make sure we are in proper schema so regoperator works correctly */
11021         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
11022
11023         /*
11024          * Fetch only those opfamily members that are tied directly to the
11025          * opfamily by pg_depend entries.
11026          *
11027          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
11028          * older server's opclass in which it is used.  This is to avoid
11029          * hard-to-detect breakage if a newer pg_dump is used to dump from an
11030          * older server and then reload into that old version.  This can go away
11031          * once 8.3 is so old as to not be of interest to anyone.
11032          */
11033         if (fout->remoteVersion >= 90100)
11034         {
11035                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11036                                                   "amopopr::pg_catalog.regoperator, "
11037                                                   "opfname AS sortfamily, "
11038                                                   "nspname AS sortfamilynsp "
11039                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
11040                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
11041                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
11042                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
11043                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11044                                                   "AND refobjid = '%u'::pg_catalog.oid "
11045                                                   "AND amopfamily = '%u'::pg_catalog.oid "
11046                                                   "ORDER BY amopstrategy",
11047                                                   opfinfo->dobj.catId.oid,
11048                                                   opfinfo->dobj.catId.oid);
11049         }
11050         else if (fout->remoteVersion >= 80400)
11051         {
11052                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11053                                                   "amopopr::pg_catalog.regoperator, "
11054                                                   "NULL AS sortfamily, "
11055                                                   "NULL AS sortfamilynsp "
11056                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11057                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11058                                                   "AND refobjid = '%u'::pg_catalog.oid "
11059                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11060                                                   "AND objid = ao.oid "
11061                                                   "ORDER BY amopstrategy",
11062                                                   opfinfo->dobj.catId.oid);
11063         }
11064         else
11065         {
11066                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
11067                                                   "amopopr::pg_catalog.regoperator, "
11068                                                   "NULL AS sortfamily, "
11069                                                   "NULL AS sortfamilynsp "
11070                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11071                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11072                                                   "AND refobjid = '%u'::pg_catalog.oid "
11073                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11074                                                   "AND objid = ao.oid "
11075                                                   "ORDER BY amopstrategy",
11076                                                   opfinfo->dobj.catId.oid);
11077         }
11078
11079         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11080
11081         resetPQExpBuffer(query);
11082
11083         appendPQExpBuffer(query, "SELECT amprocnum, "
11084                                           "amproc::pg_catalog.regprocedure, "
11085                                           "amproclefttype::pg_catalog.regtype, "
11086                                           "amprocrighttype::pg_catalog.regtype "
11087                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
11088                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11089                                           "AND refobjid = '%u'::pg_catalog.oid "
11090                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
11091                                           "AND objid = ap.oid "
11092                                           "ORDER BY amprocnum",
11093                                           opfinfo->dobj.catId.oid);
11094
11095         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11096
11097         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
11098         {
11099                 /* No loose members, so check contained opclasses */
11100                 resetPQExpBuffer(query);
11101
11102                 appendPQExpBuffer(query, "SELECT 1 "
11103                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
11104                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
11105                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11106                                                   "AND refobjid = f.oid "
11107                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11108                                                   "AND objid = c.oid "
11109                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
11110                                                   "LIMIT 1",
11111                                                   opfinfo->dobj.catId.oid);
11112
11113                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11114
11115                 if (PQntuples(res) == 0)
11116                 {
11117                         /* no need to dump it, so bail out */
11118                         PQclear(res);
11119                         PQclear(res_ops);
11120                         PQclear(res_procs);
11121                         destroyPQExpBuffer(query);
11122                         destroyPQExpBuffer(q);
11123                         destroyPQExpBuffer(delq);
11124                         destroyPQExpBuffer(labelq);
11125                         return;
11126                 }
11127
11128                 PQclear(res);
11129         }
11130
11131         /* Get additional fields from the pg_opfamily row */
11132         resetPQExpBuffer(query);
11133
11134         appendPQExpBuffer(query, "SELECT "
11135          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11136                                           "FROM pg_catalog.pg_opfamily "
11137                                           "WHERE oid = '%u'::pg_catalog.oid",
11138                                           opfinfo->dobj.catId.oid);
11139
11140         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11141
11142         i_amname = PQfnumber(res, "amname");
11143
11144         /* amname will still be needed after we PQclear res */
11145         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11146
11147         /*
11148          * DROP must be fully qualified in case same name appears in pg_catalog
11149          */
11150         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11151                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11152         appendPQExpBuffer(delq, ".%s",
11153                                           fmtId(opfinfo->dobj.name));
11154         appendPQExpBuffer(delq, " USING %s;\n",
11155                                           fmtId(amname));
11156
11157         /* Build the fixed portion of the CREATE command */
11158         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11159                                           fmtId(opfinfo->dobj.name));
11160         appendPQExpBuffer(q, " USING %s;\n",
11161                                           fmtId(amname));
11162
11163         PQclear(res);
11164
11165         /* Do we need an ALTER to add loose members? */
11166         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11167         {
11168                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11169                                                   fmtId(opfinfo->dobj.name));
11170                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11171                                                   fmtId(amname));
11172
11173                 needComma = false;
11174
11175                 /*
11176                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11177                  */
11178                 ntups = PQntuples(res_ops);
11179
11180                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11181                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11182                 i_amopopr = PQfnumber(res_ops, "amopopr");
11183                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11184                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11185
11186                 for (i = 0; i < ntups; i++)
11187                 {
11188                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11189                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11190                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11191                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11192                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11193
11194                         if (needComma)
11195                                 appendPQExpBuffer(q, " ,\n    ");
11196
11197                         appendPQExpBuffer(q, "OPERATOR %s %s",
11198                                                           amopstrategy, amopopr);
11199
11200                         if (strlen(sortfamily) > 0)
11201                         {
11202                                 appendPQExpBuffer(q, " FOR ORDER BY ");
11203                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11204                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11205                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
11206                         }
11207
11208                         if (strcmp(amopreqcheck, "t") == 0)
11209                                 appendPQExpBuffer(q, " RECHECK");
11210
11211                         needComma = true;
11212                 }
11213
11214                 /*
11215                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11216                  */
11217                 ntups = PQntuples(res_procs);
11218
11219                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11220                 i_amproc = PQfnumber(res_procs, "amproc");
11221                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11222                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11223
11224                 for (i = 0; i < ntups; i++)
11225                 {
11226                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11227                         amproc = PQgetvalue(res_procs, i, i_amproc);
11228                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11229                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11230
11231                         if (needComma)
11232                                 appendPQExpBuffer(q, " ,\n    ");
11233
11234                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11235                                                           amprocnum, amproclefttype, amprocrighttype,
11236                                                           amproc);
11237
11238                         needComma = true;
11239                 }
11240
11241                 appendPQExpBuffer(q, ";\n");
11242         }
11243
11244         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11245                                           fmtId(opfinfo->dobj.name));
11246         appendPQExpBuffer(labelq, " USING %s",
11247                                           fmtId(amname));
11248
11249         if (binary_upgrade)
11250                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11251
11252         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11253                                  opfinfo->dobj.name,
11254                                  opfinfo->dobj.namespace->dobj.name,
11255                                  NULL,
11256                                  opfinfo->rolname,
11257                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11258                                  q->data, delq->data, NULL,
11259                                  NULL, 0,
11260                                  NULL, NULL);
11261
11262         /* Dump Operator Family Comments */
11263         dumpComment(fout, labelq->data,
11264                                 NULL, opfinfo->rolname,
11265                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11266
11267         free(amname);
11268         PQclear(res_ops);
11269         PQclear(res_procs);
11270         destroyPQExpBuffer(query);
11271         destroyPQExpBuffer(q);
11272         destroyPQExpBuffer(delq);
11273         destroyPQExpBuffer(labelq);
11274 }
11275
11276 /*
11277  * dumpCollation
11278  *        write out a single collation definition
11279  */
11280 static void
11281 dumpCollation(Archive *fout, CollInfo *collinfo)
11282 {
11283         PQExpBuffer query;
11284         PQExpBuffer q;
11285         PQExpBuffer delq;
11286         PQExpBuffer labelq;
11287         PGresult   *res;
11288         int                     i_collcollate;
11289         int                     i_collctype;
11290         const char *collcollate;
11291         const char *collctype;
11292
11293         /* Skip if not to be dumped */
11294         if (!collinfo->dobj.dump || dataOnly)
11295                 return;
11296
11297         query = createPQExpBuffer();
11298         q = createPQExpBuffer();
11299         delq = createPQExpBuffer();
11300         labelq = createPQExpBuffer();
11301
11302         /* Make sure we are in proper schema */
11303         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11304
11305         /* Get conversion-specific details */
11306         appendPQExpBuffer(query, "SELECT "
11307                                           "collcollate, "
11308                                           "collctype "
11309                                           "FROM pg_catalog.pg_collation c "
11310                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11311                                           collinfo->dobj.catId.oid);
11312
11313         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11314
11315         i_collcollate = PQfnumber(res, "collcollate");
11316         i_collctype = PQfnumber(res, "collctype");
11317
11318         collcollate = PQgetvalue(res, 0, i_collcollate);
11319         collctype = PQgetvalue(res, 0, i_collctype);
11320
11321         /*
11322          * DROP must be fully qualified in case same name appears in pg_catalog
11323          */
11324         appendPQExpBuffer(delq, "DROP COLLATION %s",
11325                                           fmtId(collinfo->dobj.namespace->dobj.name));
11326         appendPQExpBuffer(delq, ".%s;\n",
11327                                           fmtId(collinfo->dobj.name));
11328
11329         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11330                                           fmtId(collinfo->dobj.name));
11331         appendStringLiteralAH(q, collcollate, fout);
11332         appendPQExpBuffer(q, ", lc_ctype = ");
11333         appendStringLiteralAH(q, collctype, fout);
11334         appendPQExpBuffer(q, ");\n");
11335
11336         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11337
11338         if (binary_upgrade)
11339                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11340
11341         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11342                                  collinfo->dobj.name,
11343                                  collinfo->dobj.namespace->dobj.name,
11344                                  NULL,
11345                                  collinfo->rolname,
11346                                  false, "COLLATION", SECTION_PRE_DATA,
11347                                  q->data, delq->data, NULL,
11348                                  NULL, 0,
11349                                  NULL, NULL);
11350
11351         /* Dump Collation Comments */
11352         dumpComment(fout, labelq->data,
11353                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11354                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11355
11356         PQclear(res);
11357
11358         destroyPQExpBuffer(query);
11359         destroyPQExpBuffer(q);
11360         destroyPQExpBuffer(delq);
11361         destroyPQExpBuffer(labelq);
11362 }
11363
11364 /*
11365  * dumpConversion
11366  *        write out a single conversion definition
11367  */
11368 static void
11369 dumpConversion(Archive *fout, ConvInfo *convinfo)
11370 {
11371         PQExpBuffer query;
11372         PQExpBuffer q;
11373         PQExpBuffer delq;
11374         PQExpBuffer labelq;
11375         PGresult   *res;
11376         int                     i_conforencoding;
11377         int                     i_contoencoding;
11378         int                     i_conproc;
11379         int                     i_condefault;
11380         const char *conforencoding;
11381         const char *contoencoding;
11382         const char *conproc;
11383         bool            condefault;
11384
11385         /* Skip if not to be dumped */
11386         if (!convinfo->dobj.dump || dataOnly)
11387                 return;
11388
11389         query = createPQExpBuffer();
11390         q = createPQExpBuffer();
11391         delq = createPQExpBuffer();
11392         labelq = createPQExpBuffer();
11393
11394         /* Make sure we are in proper schema */
11395         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11396
11397         /* Get conversion-specific details */
11398         appendPQExpBuffer(query, "SELECT "
11399                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11400                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11401                                           "conproc, condefault "
11402                                           "FROM pg_catalog.pg_conversion c "
11403                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11404                                           convinfo->dobj.catId.oid);
11405
11406         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11407
11408         i_conforencoding = PQfnumber(res, "conforencoding");
11409         i_contoencoding = PQfnumber(res, "contoencoding");
11410         i_conproc = PQfnumber(res, "conproc");
11411         i_condefault = PQfnumber(res, "condefault");
11412
11413         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11414         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11415         conproc = PQgetvalue(res, 0, i_conproc);
11416         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11417
11418         /*
11419          * DROP must be fully qualified in case same name appears in pg_catalog
11420          */
11421         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11422                                           fmtId(convinfo->dobj.namespace->dobj.name));
11423         appendPQExpBuffer(delq, ".%s;\n",
11424                                           fmtId(convinfo->dobj.name));
11425
11426         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11427                                           (condefault) ? "DEFAULT " : "",
11428                                           fmtId(convinfo->dobj.name));
11429         appendStringLiteralAH(q, conforencoding, fout);
11430         appendPQExpBuffer(q, " TO ");
11431         appendStringLiteralAH(q, contoencoding, fout);
11432         /* regproc is automatically quoted in 7.3 and above */
11433         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11434
11435         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11436
11437         if (binary_upgrade)
11438                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11439
11440         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11441                                  convinfo->dobj.name,
11442                                  convinfo->dobj.namespace->dobj.name,
11443                                  NULL,
11444                                  convinfo->rolname,
11445                                  false, "CONVERSION", SECTION_PRE_DATA,
11446                                  q->data, delq->data, NULL,
11447                                  NULL, 0,
11448                                  NULL, NULL);
11449
11450         /* Dump Conversion Comments */
11451         dumpComment(fout, labelq->data,
11452                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11453                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11454
11455         PQclear(res);
11456
11457         destroyPQExpBuffer(query);
11458         destroyPQExpBuffer(q);
11459         destroyPQExpBuffer(delq);
11460         destroyPQExpBuffer(labelq);
11461 }
11462
11463 /*
11464  * format_aggregate_signature: generate aggregate name and argument list
11465  *
11466  * The argument type names are qualified if needed.  The aggregate name
11467  * is never qualified.
11468  */
11469 static char *
11470 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11471 {
11472         PQExpBufferData buf;
11473         int                     j;
11474
11475         initPQExpBuffer(&buf);
11476         if (honor_quotes)
11477                 appendPQExpBuffer(&buf, "%s",
11478                                                   fmtId(agginfo->aggfn.dobj.name));
11479         else
11480                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
11481
11482         if (agginfo->aggfn.nargs == 0)
11483                 appendPQExpBuffer(&buf, "(*)");
11484         else
11485         {
11486                 appendPQExpBuffer(&buf, "(");
11487                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11488                 {
11489                         char       *typname;
11490
11491                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11492                                                                                    zeroAsOpaque);
11493
11494                         appendPQExpBuffer(&buf, "%s%s",
11495                                                           (j > 0) ? ", " : "",
11496                                                           typname);
11497                         free(typname);
11498                 }
11499                 appendPQExpBuffer(&buf, ")");
11500         }
11501         return buf.data;
11502 }
11503
11504 /*
11505  * dumpAgg
11506  *        write out a single aggregate definition
11507  */
11508 static void
11509 dumpAgg(Archive *fout, AggInfo *agginfo)
11510 {
11511         PQExpBuffer query;
11512         PQExpBuffer q;
11513         PQExpBuffer delq;
11514         PQExpBuffer labelq;
11515         PQExpBuffer details;
11516         char       *aggsig;                     /* identity signature */
11517         char       *aggfullsig;         /* full signature */
11518         char       *aggsig_tag;
11519         PGresult   *res;
11520         int                     i_aggtransfn;
11521         int                     i_aggfinalfn;
11522         int                     i_aggsortop;
11523         int                     i_aggtranstype;
11524         int                     i_aggtransspace;
11525         int                     i_agginitval;
11526         int                     i_convertok;
11527         const char *aggtransfn;
11528         const char *aggfinalfn;
11529         const char *aggsortop;
11530         const char *aggtranstype;
11531         const char *aggtransspace;
11532         const char *agginitval;
11533         bool            convertok;
11534
11535         /* Skip if not to be dumped */
11536         if (!agginfo->aggfn.dobj.dump || dataOnly)
11537                 return;
11538
11539         query = createPQExpBuffer();
11540         q = createPQExpBuffer();
11541         delq = createPQExpBuffer();
11542         labelq = createPQExpBuffer();
11543         details = createPQExpBuffer();
11544
11545         /* Make sure we are in proper schema */
11546         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11547
11548         /* Get aggregate-specific details */
11549         if (fout->remoteVersion >= 90400)
11550         {
11551                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11552                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11553                                                   "aggsortop::pg_catalog.regoperator, "
11554                                                   "aggtransspace, agginitval, "
11555                                                   "'t'::boolean AS convertok, "
11556                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11557                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11558                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11559                                                   "WHERE a.aggfnoid = p.oid "
11560                                                   "AND p.oid = '%u'::pg_catalog.oid",
11561                                                   agginfo->aggfn.dobj.catId.oid);
11562         }
11563         else if (fout->remoteVersion >= 80400)
11564         {
11565                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11566                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11567                                                   "aggsortop::pg_catalog.regoperator, "
11568                                                   "0 AS aggtransspace, agginitval, "
11569                                                   "'t'::boolean AS convertok, "
11570                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11571                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11572                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11573                                                   "WHERE a.aggfnoid = p.oid "
11574                                                   "AND p.oid = '%u'::pg_catalog.oid",
11575                                                   agginfo->aggfn.dobj.catId.oid);
11576         }
11577         else if (fout->remoteVersion >= 80100)
11578         {
11579                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11580                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11581                                                   "aggsortop::pg_catalog.regoperator, "
11582                                                   "0 AS aggtransspace, agginitval, "
11583                                                   "'t'::boolean AS convertok "
11584                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11585                                                   "WHERE a.aggfnoid = p.oid "
11586                                                   "AND p.oid = '%u'::pg_catalog.oid",
11587                                                   agginfo->aggfn.dobj.catId.oid);
11588         }
11589         else if (fout->remoteVersion >= 70300)
11590         {
11591                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11592                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11593                                                   "0 AS aggsortop, "
11594                                                   "0 AS aggtransspace, agginitval, "
11595                                                   "'t'::boolean AS convertok "
11596                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11597                                                   "WHERE a.aggfnoid = p.oid "
11598                                                   "AND p.oid = '%u'::pg_catalog.oid",
11599                                                   agginfo->aggfn.dobj.catId.oid);
11600         }
11601         else if (fout->remoteVersion >= 70100)
11602         {
11603                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11604                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11605                                                   "0 AS aggsortop, "
11606                                                   "0 AS aggtransspace, agginitval, "
11607                                                   "'t'::boolean AS convertok "
11608                                                   "FROM pg_aggregate "
11609                                                   "WHERE oid = '%u'::oid",
11610                                                   agginfo->aggfn.dobj.catId.oid);
11611         }
11612         else
11613         {
11614                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11615                                                   "aggfinalfn, "
11616                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11617                                                   "0 AS aggsortop, "
11618                                                   "0 AS aggtransspace, agginitval1 AS agginitval, "
11619                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11620                                                   "FROM pg_aggregate "
11621                                                   "WHERE oid = '%u'::oid",
11622                                                   agginfo->aggfn.dobj.catId.oid);
11623         }
11624
11625         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11626
11627         i_aggtransfn = PQfnumber(res, "aggtransfn");
11628         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11629         i_aggsortop = PQfnumber(res, "aggsortop");
11630         i_aggtranstype = PQfnumber(res, "aggtranstype");
11631         i_aggtransspace = PQfnumber(res, "aggtransspace");
11632         i_agginitval = PQfnumber(res, "agginitval");
11633         i_convertok = PQfnumber(res, "convertok");
11634
11635         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11636         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11637         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11638         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11639         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
11640         agginitval = PQgetvalue(res, 0, i_agginitval);
11641         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11642
11643         if (fout->remoteVersion >= 80400)
11644         {
11645                 /* 8.4 or later; we rely on server-side code for most of the work */
11646                 char       *funcargs;
11647                 char       *funciargs;
11648
11649                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11650                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11651                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
11652                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
11653         }
11654         else
11655         {
11656                 /* pre-8.4, do it ourselves */
11657                 aggsig = format_aggregate_signature(agginfo, fout, true);
11658                 aggfullsig = aggsig;
11659         }
11660
11661         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11662
11663         if (!convertok)
11664         {
11665                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11666                                   aggsig);
11667                 return;
11668         }
11669
11670         if (fout->remoteVersion >= 70300)
11671         {
11672                 /* If using 7.3's regproc or regtype, data is already quoted */
11673                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11674                                                   aggtransfn,
11675                                                   aggtranstype);
11676         }
11677         else if (fout->remoteVersion >= 70100)
11678         {
11679                 /* format_type quotes, regproc does not */
11680                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11681                                                   fmtId(aggtransfn),
11682                                                   aggtranstype);
11683         }
11684         else
11685         {
11686                 /* need quotes all around */
11687                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11688                                                   fmtId(aggtransfn));
11689                 appendPQExpBuffer(details, "    STYPE = %s",
11690                                                   fmtId(aggtranstype));
11691         }
11692
11693         if (strcmp(aggtransspace, "0") != 0)
11694         {
11695                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
11696                                                   aggtransspace);
11697         }
11698
11699         if (!PQgetisnull(res, 0, i_agginitval))
11700         {
11701                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11702                 appendStringLiteralAH(details, agginitval, fout);
11703         }
11704
11705         if (strcmp(aggfinalfn, "-") != 0)
11706         {
11707                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11708                                                   aggfinalfn);
11709         }
11710
11711         aggsortop = convertOperatorReference(fout, aggsortop);
11712         if (aggsortop)
11713         {
11714                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11715                                                   aggsortop);
11716         }
11717
11718         /*
11719          * DROP must be fully qualified in case same name appears in pg_catalog
11720          */
11721         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11722                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11723                                           aggsig);
11724
11725         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11726                                           aggfullsig, details->data);
11727
11728         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11729
11730         if (binary_upgrade)
11731                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11732
11733         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11734                                  aggsig_tag,
11735                                  agginfo->aggfn.dobj.namespace->dobj.name,
11736                                  NULL,
11737                                  agginfo->aggfn.rolname,
11738                                  false, "AGGREGATE", SECTION_PRE_DATA,
11739                                  q->data, delq->data, NULL,
11740                                  NULL, 0,
11741                                  NULL, NULL);
11742
11743         /* Dump Aggregate Comments */
11744         dumpComment(fout, labelq->data,
11745                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11746                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11747         dumpSecLabel(fout, labelq->data,
11748                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11749                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11750
11751         /*
11752          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11753          * command look like a function's GRANT; in particular this affects the
11754          * syntax for zero-argument aggregates.
11755          */
11756         free(aggsig);
11757         free(aggsig_tag);
11758
11759         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11760         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11761
11762         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11763                         "FUNCTION",
11764                         aggsig, NULL, aggsig_tag,
11765                         agginfo->aggfn.dobj.namespace->dobj.name,
11766                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11767
11768         free(aggsig);
11769         free(aggsig_tag);
11770
11771         PQclear(res);
11772
11773         destroyPQExpBuffer(query);
11774         destroyPQExpBuffer(q);
11775         destroyPQExpBuffer(delq);
11776         destroyPQExpBuffer(labelq);
11777         destroyPQExpBuffer(details);
11778 }
11779
11780 /*
11781  * dumpTSParser
11782  *        write out a single text search parser
11783  */
11784 static void
11785 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11786 {
11787         PQExpBuffer q;
11788         PQExpBuffer delq;
11789         PQExpBuffer labelq;
11790
11791         /* Skip if not to be dumped */
11792         if (!prsinfo->dobj.dump || dataOnly)
11793                 return;
11794
11795         q = createPQExpBuffer();
11796         delq = createPQExpBuffer();
11797         labelq = createPQExpBuffer();
11798
11799         /* Make sure we are in proper schema */
11800         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11801
11802         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11803                                           fmtId(prsinfo->dobj.name));
11804
11805         appendPQExpBuffer(q, "    START = %s,\n",
11806                                           convertTSFunction(fout, prsinfo->prsstart));
11807         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11808                                           convertTSFunction(fout, prsinfo->prstoken));
11809         appendPQExpBuffer(q, "    END = %s,\n",
11810                                           convertTSFunction(fout, prsinfo->prsend));
11811         if (prsinfo->prsheadline != InvalidOid)
11812                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11813                                                   convertTSFunction(fout, prsinfo->prsheadline));
11814         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11815                                           convertTSFunction(fout, prsinfo->prslextype));
11816
11817         /*
11818          * DROP must be fully qualified in case same name appears in pg_catalog
11819          */
11820         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11821                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11822         appendPQExpBuffer(delq, ".%s;\n",
11823                                           fmtId(prsinfo->dobj.name));
11824
11825         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11826                                           fmtId(prsinfo->dobj.name));
11827
11828         if (binary_upgrade)
11829                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11830
11831         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11832                                  prsinfo->dobj.name,
11833                                  prsinfo->dobj.namespace->dobj.name,
11834                                  NULL,
11835                                  "",
11836                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11837                                  q->data, delq->data, NULL,
11838                                  NULL, 0,
11839                                  NULL, NULL);
11840
11841         /* Dump Parser Comments */
11842         dumpComment(fout, labelq->data,
11843                                 NULL, "",
11844                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11845
11846         destroyPQExpBuffer(q);
11847         destroyPQExpBuffer(delq);
11848         destroyPQExpBuffer(labelq);
11849 }
11850
11851 /*
11852  * dumpTSDictionary
11853  *        write out a single text search dictionary
11854  */
11855 static void
11856 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11857 {
11858         PQExpBuffer q;
11859         PQExpBuffer delq;
11860         PQExpBuffer labelq;
11861         PQExpBuffer query;
11862         PGresult   *res;
11863         char       *nspname;
11864         char       *tmplname;
11865
11866         /* Skip if not to be dumped */
11867         if (!dictinfo->dobj.dump || dataOnly)
11868                 return;
11869
11870         q = createPQExpBuffer();
11871         delq = createPQExpBuffer();
11872         labelq = createPQExpBuffer();
11873         query = createPQExpBuffer();
11874
11875         /* Fetch name and namespace of the dictionary's template */
11876         selectSourceSchema(fout, "pg_catalog");
11877         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11878                                           "FROM pg_ts_template p, pg_namespace n "
11879                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11880                                           dictinfo->dicttemplate);
11881         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11882         nspname = PQgetvalue(res, 0, 0);
11883         tmplname = PQgetvalue(res, 0, 1);
11884
11885         /* Make sure we are in proper schema */
11886         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11887
11888         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11889                                           fmtId(dictinfo->dobj.name));
11890
11891         appendPQExpBuffer(q, "    TEMPLATE = ");
11892         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11893                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11894         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11895
11896         PQclear(res);
11897
11898         /* the dictinitoption can be dumped straight into the command */
11899         if (dictinfo->dictinitoption)
11900                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11901
11902         appendPQExpBuffer(q, " );\n");
11903
11904         /*
11905          * DROP must be fully qualified in case same name appears in pg_catalog
11906          */
11907         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11908                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11909         appendPQExpBuffer(delq, ".%s;\n",
11910                                           fmtId(dictinfo->dobj.name));
11911
11912         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11913                                           fmtId(dictinfo->dobj.name));
11914
11915         if (binary_upgrade)
11916                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11917
11918         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11919                                  dictinfo->dobj.name,
11920                                  dictinfo->dobj.namespace->dobj.name,
11921                                  NULL,
11922                                  dictinfo->rolname,
11923                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11924                                  q->data, delq->data, NULL,
11925                                  NULL, 0,
11926                                  NULL, NULL);
11927
11928         /* Dump Dictionary Comments */
11929         dumpComment(fout, labelq->data,
11930                                 NULL, dictinfo->rolname,
11931                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11932
11933         destroyPQExpBuffer(q);
11934         destroyPQExpBuffer(delq);
11935         destroyPQExpBuffer(labelq);
11936         destroyPQExpBuffer(query);
11937 }
11938
11939 /*
11940  * dumpTSTemplate
11941  *        write out a single text search template
11942  */
11943 static void
11944 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11945 {
11946         PQExpBuffer q;
11947         PQExpBuffer delq;
11948         PQExpBuffer labelq;
11949
11950         /* Skip if not to be dumped */
11951         if (!tmplinfo->dobj.dump || dataOnly)
11952                 return;
11953
11954         q = createPQExpBuffer();
11955         delq = createPQExpBuffer();
11956         labelq = createPQExpBuffer();
11957
11958         /* Make sure we are in proper schema */
11959         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11960
11961         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11962                                           fmtId(tmplinfo->dobj.name));
11963
11964         if (tmplinfo->tmplinit != InvalidOid)
11965                 appendPQExpBuffer(q, "    INIT = %s,\n",
11966                                                   convertTSFunction(fout, tmplinfo->tmplinit));
11967         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11968                                           convertTSFunction(fout, tmplinfo->tmpllexize));
11969
11970         /*
11971          * DROP must be fully qualified in case same name appears in pg_catalog
11972          */
11973         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11974                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11975         appendPQExpBuffer(delq, ".%s;\n",
11976                                           fmtId(tmplinfo->dobj.name));
11977
11978         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11979                                           fmtId(tmplinfo->dobj.name));
11980
11981         if (binary_upgrade)
11982                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11983
11984         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11985                                  tmplinfo->dobj.name,
11986                                  tmplinfo->dobj.namespace->dobj.name,
11987                                  NULL,
11988                                  "",
11989                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11990                                  q->data, delq->data, NULL,
11991                                  NULL, 0,
11992                                  NULL, NULL);
11993
11994         /* Dump Template Comments */
11995         dumpComment(fout, labelq->data,
11996                                 NULL, "",
11997                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11998
11999         destroyPQExpBuffer(q);
12000         destroyPQExpBuffer(delq);
12001         destroyPQExpBuffer(labelq);
12002 }
12003
12004 /*
12005  * dumpTSConfig
12006  *        write out a single text search configuration
12007  */
12008 static void
12009 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
12010 {
12011         PQExpBuffer q;
12012         PQExpBuffer delq;
12013         PQExpBuffer labelq;
12014         PQExpBuffer query;
12015         PGresult   *res;
12016         char       *nspname;
12017         char       *prsname;
12018         int                     ntups,
12019                                 i;
12020         int                     i_tokenname;
12021         int                     i_dictname;
12022
12023         /* Skip if not to be dumped */
12024         if (!cfginfo->dobj.dump || dataOnly)
12025                 return;
12026
12027         q = createPQExpBuffer();
12028         delq = createPQExpBuffer();
12029         labelq = createPQExpBuffer();
12030         query = createPQExpBuffer();
12031
12032         /* Fetch name and namespace of the config's parser */
12033         selectSourceSchema(fout, "pg_catalog");
12034         appendPQExpBuffer(query, "SELECT nspname, prsname "
12035                                           "FROM pg_ts_parser p, pg_namespace n "
12036                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
12037                                           cfginfo->cfgparser);
12038         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12039         nspname = PQgetvalue(res, 0, 0);
12040         prsname = PQgetvalue(res, 0, 1);
12041
12042         /* Make sure we are in proper schema */
12043         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
12044
12045         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
12046                                           fmtId(cfginfo->dobj.name));
12047
12048         appendPQExpBuffer(q, "    PARSER = ");
12049         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
12050                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
12051         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
12052
12053         PQclear(res);
12054
12055         resetPQExpBuffer(query);
12056         appendPQExpBuffer(query,
12057                                           "SELECT \n"
12058                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
12059                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
12060                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
12061                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
12062                                           "WHERE m.mapcfg = '%u' \n"
12063                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
12064                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
12065
12066         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12067         ntups = PQntuples(res);
12068
12069         i_tokenname = PQfnumber(res, "tokenname");
12070         i_dictname = PQfnumber(res, "dictname");
12071
12072         for (i = 0; i < ntups; i++)
12073         {
12074                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
12075                 char       *dictname = PQgetvalue(res, i, i_dictname);
12076
12077                 if (i == 0 ||
12078                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
12079                 {
12080                         /* starting a new token type, so start a new command */
12081                         if (i > 0)
12082                                 appendPQExpBuffer(q, ";\n");
12083                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
12084                                                           fmtId(cfginfo->dobj.name));
12085                         /* tokenname needs quoting, dictname does NOT */
12086                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
12087                                                           fmtId(tokenname), dictname);
12088                 }
12089                 else
12090                         appendPQExpBuffer(q, ", %s", dictname);
12091         }
12092
12093         if (ntups > 0)
12094                 appendPQExpBuffer(q, ";\n");
12095
12096         PQclear(res);
12097
12098         /*
12099          * DROP must be fully qualified in case same name appears in pg_catalog
12100          */
12101         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
12102                                           fmtId(cfginfo->dobj.namespace->dobj.name));
12103         appendPQExpBuffer(delq, ".%s;\n",
12104                                           fmtId(cfginfo->dobj.name));
12105
12106         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
12107                                           fmtId(cfginfo->dobj.name));
12108
12109         if (binary_upgrade)
12110                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
12111
12112         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
12113                                  cfginfo->dobj.name,
12114                                  cfginfo->dobj.namespace->dobj.name,
12115                                  NULL,
12116                                  cfginfo->rolname,
12117                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
12118                                  q->data, delq->data, NULL,
12119                                  NULL, 0,
12120                                  NULL, NULL);
12121
12122         /* Dump Configuration Comments */
12123         dumpComment(fout, labelq->data,
12124                                 NULL, cfginfo->rolname,
12125                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
12126
12127         destroyPQExpBuffer(q);
12128         destroyPQExpBuffer(delq);
12129         destroyPQExpBuffer(labelq);
12130         destroyPQExpBuffer(query);
12131 }
12132
12133 /*
12134  * dumpForeignDataWrapper
12135  *        write out a single foreign-data wrapper definition
12136  */
12137 static void
12138 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
12139 {
12140         PQExpBuffer q;
12141         PQExpBuffer delq;
12142         PQExpBuffer labelq;
12143         char       *qfdwname;
12144
12145         /* Skip if not to be dumped */
12146         if (!fdwinfo->dobj.dump || dataOnly)
12147                 return;
12148
12149         /*
12150          * FDWs that belong to an extension are dumped based on their "dump"
12151          * field. Otherwise omit them if we are only dumping some specific object.
12152          */
12153         if (!fdwinfo->dobj.ext_member)
12154                 if (!include_everything)
12155                         return;
12156
12157         q = createPQExpBuffer();
12158         delq = createPQExpBuffer();
12159         labelq = createPQExpBuffer();
12160
12161         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
12162
12163         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
12164                                           qfdwname);
12165
12166         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
12167                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
12168
12169         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
12170                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
12171
12172         if (strlen(fdwinfo->fdwoptions) > 0)
12173                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12174
12175         appendPQExpBuffer(q, ";\n");
12176
12177         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12178                                           qfdwname);
12179
12180         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12181                                           qfdwname);
12182
12183         if (binary_upgrade)
12184                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12185
12186         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12187                                  fdwinfo->dobj.name,
12188                                  NULL,
12189                                  NULL,
12190                                  fdwinfo->rolname,
12191                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12192                                  q->data, delq->data, NULL,
12193                                  NULL, 0,
12194                                  NULL, NULL);
12195
12196         /* Handle the ACL */
12197         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12198                         "FOREIGN DATA WRAPPER",
12199                         qfdwname, NULL, fdwinfo->dobj.name,
12200                         NULL, fdwinfo->rolname,
12201                         fdwinfo->fdwacl);
12202
12203         /* Dump Foreign Data Wrapper Comments */
12204         dumpComment(fout, labelq->data,
12205                                 NULL, fdwinfo->rolname,
12206                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12207
12208         free(qfdwname);
12209
12210         destroyPQExpBuffer(q);
12211         destroyPQExpBuffer(delq);
12212         destroyPQExpBuffer(labelq);
12213 }
12214
12215 /*
12216  * dumpForeignServer
12217  *        write out a foreign server definition
12218  */
12219 static void
12220 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12221 {
12222         PQExpBuffer q;
12223         PQExpBuffer delq;
12224         PQExpBuffer labelq;
12225         PQExpBuffer query;
12226         PGresult   *res;
12227         char       *qsrvname;
12228         char       *fdwname;
12229
12230         /* Skip if not to be dumped */
12231         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12232                 return;
12233
12234         q = createPQExpBuffer();
12235         delq = createPQExpBuffer();
12236         labelq = createPQExpBuffer();
12237         query = createPQExpBuffer();
12238
12239         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12240
12241         /* look up the foreign-data wrapper */
12242         selectSourceSchema(fout, "pg_catalog");
12243         appendPQExpBuffer(query, "SELECT fdwname "
12244                                           "FROM pg_foreign_data_wrapper w "
12245                                           "WHERE w.oid = '%u'",
12246                                           srvinfo->srvfdw);
12247         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12248         fdwname = PQgetvalue(res, 0, 0);
12249
12250         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12251         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12252         {
12253                 appendPQExpBuffer(q, " TYPE ");
12254                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12255         }
12256         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12257         {
12258                 appendPQExpBuffer(q, " VERSION ");
12259                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12260         }
12261
12262         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
12263         appendPQExpBuffer(q, "%s", fmtId(fdwname));
12264
12265         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12266                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12267
12268         appendPQExpBuffer(q, ";\n");
12269
12270         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12271                                           qsrvname);
12272
12273         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12274
12275         if (binary_upgrade)
12276                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12277
12278         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12279                                  srvinfo->dobj.name,
12280                                  NULL,
12281                                  NULL,
12282                                  srvinfo->rolname,
12283                                  false, "SERVER", SECTION_PRE_DATA,
12284                                  q->data, delq->data, NULL,
12285                                  NULL, 0,
12286                                  NULL, NULL);
12287
12288         /* Handle the ACL */
12289         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12290                         "FOREIGN SERVER",
12291                         qsrvname, NULL, srvinfo->dobj.name,
12292                         NULL, srvinfo->rolname,
12293                         srvinfo->srvacl);
12294
12295         /* Dump user mappings */
12296         dumpUserMappings(fout,
12297                                          srvinfo->dobj.name, NULL,
12298                                          srvinfo->rolname,
12299                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12300
12301         /* Dump Foreign Server Comments */
12302         dumpComment(fout, labelq->data,
12303                                 NULL, srvinfo->rolname,
12304                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12305
12306         free(qsrvname);
12307
12308         destroyPQExpBuffer(q);
12309         destroyPQExpBuffer(delq);
12310         destroyPQExpBuffer(labelq);
12311 }
12312
12313 /*
12314  * dumpUserMappings
12315  *
12316  * This routine is used to dump any user mappings associated with the
12317  * server handed to this routine. Should be called after ArchiveEntry()
12318  * for the server.
12319  */
12320 static void
12321 dumpUserMappings(Archive *fout,
12322                                  const char *servername, const char *namespace,
12323                                  const char *owner,
12324                                  CatalogId catalogId, DumpId dumpId)
12325 {
12326         PQExpBuffer q;
12327         PQExpBuffer delq;
12328         PQExpBuffer query;
12329         PQExpBuffer tag;
12330         PGresult   *res;
12331         int                     ntups;
12332         int                     i_usename;
12333         int                     i_umoptions;
12334         int                     i;
12335
12336         q = createPQExpBuffer();
12337         tag = createPQExpBuffer();
12338         delq = createPQExpBuffer();
12339         query = createPQExpBuffer();
12340
12341         /*
12342          * We read from the publicly accessible view pg_user_mappings, so as not
12343          * to fail if run by a non-superuser.  Note that the view will show
12344          * umoptions as null if the user hasn't got privileges for the associated
12345          * server; this means that pg_dump will dump such a mapping, but with no
12346          * OPTIONS clause.      A possible alternative is to skip such mappings
12347          * altogether, but it's not clear that that's an improvement.
12348          */
12349         selectSourceSchema(fout, "pg_catalog");
12350
12351         appendPQExpBuffer(query,
12352                                           "SELECT usename, "
12353                                           "array_to_string(ARRAY("
12354                                           "SELECT quote_ident(option_name) || ' ' || "
12355                                           "quote_literal(option_value) "
12356                                           "FROM pg_options_to_table(umoptions) "
12357                                           "ORDER BY option_name"
12358                                           "), E',\n    ') AS umoptions "
12359                                           "FROM pg_user_mappings "
12360                                           "WHERE srvid = '%u' "
12361                                           "ORDER BY usename",
12362                                           catalogId.oid);
12363
12364         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12365
12366         ntups = PQntuples(res);
12367         i_usename = PQfnumber(res, "usename");
12368         i_umoptions = PQfnumber(res, "umoptions");
12369
12370         for (i = 0; i < ntups; i++)
12371         {
12372                 char       *usename;
12373                 char       *umoptions;
12374
12375                 usename = PQgetvalue(res, i, i_usename);
12376                 umoptions = PQgetvalue(res, i, i_umoptions);
12377
12378                 resetPQExpBuffer(q);
12379                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12380                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12381
12382                 if (umoptions && strlen(umoptions) > 0)
12383                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12384
12385                 appendPQExpBuffer(q, ";\n");
12386
12387                 resetPQExpBuffer(delq);
12388                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12389                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12390
12391                 resetPQExpBuffer(tag);
12392                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12393                                                   usename, servername);
12394
12395                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12396                                          tag->data,
12397                                          namespace,
12398                                          NULL,
12399                                          owner, false,
12400                                          "USER MAPPING", SECTION_PRE_DATA,
12401                                          q->data, delq->data, NULL,
12402                                          &dumpId, 1,
12403                                          NULL, NULL);
12404         }
12405
12406         PQclear(res);
12407
12408         destroyPQExpBuffer(query);
12409         destroyPQExpBuffer(delq);
12410         destroyPQExpBuffer(q);
12411 }
12412
12413 /*
12414  * Write out default privileges information
12415  */
12416 static void
12417 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12418 {
12419         PQExpBuffer q;
12420         PQExpBuffer tag;
12421         const char *type;
12422
12423         /* Skip if not to be dumped */
12424         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12425                 return;
12426
12427         q = createPQExpBuffer();
12428         tag = createPQExpBuffer();
12429
12430         switch (daclinfo->defaclobjtype)
12431         {
12432                 case DEFACLOBJ_RELATION:
12433                         type = "TABLES";
12434                         break;
12435                 case DEFACLOBJ_SEQUENCE:
12436                         type = "SEQUENCES";
12437                         break;
12438                 case DEFACLOBJ_FUNCTION:
12439                         type = "FUNCTIONS";
12440                         break;
12441                 case DEFACLOBJ_TYPE:
12442                         type = "TYPES";
12443                         break;
12444                 default:
12445                         /* shouldn't get here */
12446                         exit_horribly(NULL,
12447                                           "unrecognized object type in default privileges: %d\n",
12448                                                   (int) daclinfo->defaclobjtype);
12449                         type = "";                      /* keep compiler quiet */
12450         }
12451
12452         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12453
12454         /* build the actual command(s) for this tuple */
12455         if (!buildDefaultACLCommands(type,
12456                                                                  daclinfo->dobj.namespace != NULL ?
12457                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12458                                                                  daclinfo->defaclacl,
12459                                                                  daclinfo->defaclrole,
12460                                                                  fout->remoteVersion,
12461                                                                  q))
12462                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12463                                           daclinfo->defaclacl);
12464
12465         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12466                                  tag->data,
12467            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12468                                  NULL,
12469                                  daclinfo->defaclrole,
12470                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12471                                  q->data, "", NULL,
12472                                  NULL, 0,
12473                                  NULL, NULL);
12474
12475         destroyPQExpBuffer(tag);
12476         destroyPQExpBuffer(q);
12477 }
12478
12479 /*----------
12480  * Write out grant/revoke information
12481  *
12482  * 'objCatId' is the catalog ID of the underlying object.
12483  * 'objDumpId' is the dump ID of the underlying object.
12484  * 'type' must be one of
12485  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12486  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12487  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12488  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12489  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12490  * 'nspname' is the namespace the object is in (NULL if none).
12491  * 'owner' is the owner, NULL if there is no owner (for languages).
12492  * 'acls' is the string read out of the fooacl system catalog field;
12493  *              it will be parsed here.
12494  *----------
12495  */
12496 static void
12497 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12498                 const char *type, const char *name, const char *subname,
12499                 const char *tag, const char *nspname, const char *owner,
12500                 const char *acls)
12501 {
12502         PQExpBuffer sql;
12503
12504         /* Do nothing if ACL dump is not enabled */
12505         if (aclsSkip)
12506                 return;
12507
12508         /* --data-only skips ACLs *except* BLOB ACLs */
12509         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12510                 return;
12511
12512         sql = createPQExpBuffer();
12513
12514         if (!buildACLCommands(name, subname, type, acls, owner,
12515                                                   "", fout->remoteVersion, sql))
12516                 exit_horribly(NULL,
12517                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12518                                           acls, name, type);
12519
12520         if (sql->len > 0)
12521                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12522                                          tag, nspname,
12523                                          NULL,
12524                                          owner ? owner : "",
12525                                          false, "ACL", SECTION_NONE,
12526                                          sql->data, "", NULL,
12527                                          &(objDumpId), 1,
12528                                          NULL, NULL);
12529
12530         destroyPQExpBuffer(sql);
12531 }
12532
12533 /*
12534  * dumpSecLabel
12535  *
12536  * This routine is used to dump any security labels associated with the
12537  * object handed to this routine. The routine takes a constant character
12538  * string for the target part of the security-label command, plus
12539  * the namespace and owner of the object (for labeling the ArchiveEntry),
12540  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12541  * plus the dump ID for the object (for setting a dependency).
12542  * If a matching pg_seclabel entry is found, it is dumped.
12543  *
12544  * Note: although this routine takes a dumpId for dependency purposes,
12545  * that purpose is just to mark the dependency in the emitted dump file
12546  * for possible future use by pg_restore.  We do NOT use it for determining
12547  * ordering of the label in the dump file, because this routine is called
12548  * after dependency sorting occurs.  This routine should be called just after
12549  * calling ArchiveEntry() for the specified object.
12550  */
12551 static void
12552 dumpSecLabel(Archive *fout, const char *target,
12553                          const char *namespace, const char *owner,
12554                          CatalogId catalogId, int subid, DumpId dumpId)
12555 {
12556         SecLabelItem *labels;
12557         int                     nlabels;
12558         int                     i;
12559         PQExpBuffer query;
12560
12561         /* do nothing, if --no-security-labels is supplied */
12562         if (no_security_labels)
12563                 return;
12564
12565         /* Comments are schema not data ... except blob comments are data */
12566         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12567         {
12568                 if (dataOnly)
12569                         return;
12570         }
12571         else
12572         {
12573                 if (schemaOnly)
12574                         return;
12575         }
12576
12577         /* Search for security labels associated with catalogId, using table */
12578         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12579
12580         query = createPQExpBuffer();
12581
12582         for (i = 0; i < nlabels; i++)
12583         {
12584                 /*
12585                  * Ignore label entries for which the subid doesn't match.
12586                  */
12587                 if (labels[i].objsubid != subid)
12588                         continue;
12589
12590                 appendPQExpBuffer(query,
12591                                                   "SECURITY LABEL FOR %s ON %s IS ",
12592                                                   fmtId(labels[i].provider), target);
12593                 appendStringLiteralAH(query, labels[i].label, fout);
12594                 appendPQExpBuffer(query, ";\n");
12595         }
12596
12597         if (query->len > 0)
12598         {
12599                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12600                                          target, namespace, NULL, owner,
12601                                          false, "SECURITY LABEL", SECTION_NONE,
12602                                          query->data, "", NULL,
12603                                          &(dumpId), 1,
12604                                          NULL, NULL);
12605         }
12606         destroyPQExpBuffer(query);
12607 }
12608
12609 /*
12610  * dumpTableSecLabel
12611  *
12612  * As above, but dump security label for both the specified table (or view)
12613  * and its columns.
12614  */
12615 static void
12616 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12617 {
12618         SecLabelItem *labels;
12619         int                     nlabels;
12620         int                     i;
12621         PQExpBuffer query;
12622         PQExpBuffer target;
12623
12624         /* do nothing, if --no-security-labels is supplied */
12625         if (no_security_labels)
12626                 return;
12627
12628         /* SecLabel are SCHEMA not data */
12629         if (dataOnly)
12630                 return;
12631
12632         /* Search for comments associated with relation, using table */
12633         nlabels = findSecLabels(fout,
12634                                                         tbinfo->dobj.catId.tableoid,
12635                                                         tbinfo->dobj.catId.oid,
12636                                                         &labels);
12637
12638         /* If security labels exist, build SECURITY LABEL statements */
12639         if (nlabels <= 0)
12640                 return;
12641
12642         query = createPQExpBuffer();
12643         target = createPQExpBuffer();
12644
12645         for (i = 0; i < nlabels; i++)
12646         {
12647                 const char *colname;
12648                 const char *provider = labels[i].provider;
12649                 const char *label = labels[i].label;
12650                 int                     objsubid = labels[i].objsubid;
12651
12652                 resetPQExpBuffer(target);
12653                 if (objsubid == 0)
12654                 {
12655                         appendPQExpBuffer(target, "%s %s", reltypename,
12656                                                           fmtId(tbinfo->dobj.name));
12657                 }
12658                 else
12659                 {
12660                         colname = getAttrName(objsubid, tbinfo);
12661                         /* first fmtId result must be consumed before calling it again */
12662                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12663                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12664                 }
12665                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12666                                                   fmtId(provider), target->data);
12667                 appendStringLiteralAH(query, label, fout);
12668                 appendPQExpBuffer(query, ";\n");
12669         }
12670         if (query->len > 0)
12671         {
12672                 resetPQExpBuffer(target);
12673                 appendPQExpBuffer(target, "%s %s", reltypename,
12674                                                   fmtId(tbinfo->dobj.name));
12675                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12676                                          target->data,
12677                                          tbinfo->dobj.namespace->dobj.name,
12678                                          NULL, tbinfo->rolname,
12679                                          false, "SECURITY LABEL", SECTION_NONE,
12680                                          query->data, "", NULL,
12681                                          &(tbinfo->dobj.dumpId), 1,
12682                                          NULL, NULL);
12683         }
12684         destroyPQExpBuffer(query);
12685         destroyPQExpBuffer(target);
12686 }
12687
12688 /*
12689  * findSecLabels
12690  *
12691  * Find the security label(s), if any, associated with the given object.
12692  * All the objsubid values associated with the given classoid/objoid are
12693  * found with one search.
12694  */
12695 static int
12696 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12697 {
12698         /* static storage for table of security labels */
12699         static SecLabelItem *labels = NULL;
12700         static int      nlabels = -1;
12701
12702         SecLabelItem *middle = NULL;
12703         SecLabelItem *low;
12704         SecLabelItem *high;
12705         int                     nmatch;
12706
12707         /* Get security labels if we didn't already */
12708         if (nlabels < 0)
12709                 nlabels = collectSecLabels(fout, &labels);
12710
12711         if (nlabels <= 0)                       /* no labels, so no match is possible */
12712         {
12713                 *items = NULL;
12714                 return 0;
12715         }
12716
12717         /*
12718          * Do binary search to find some item matching the object.
12719          */
12720         low = &labels[0];
12721         high = &labels[nlabels - 1];
12722         while (low <= high)
12723         {
12724                 middle = low + (high - low) / 2;
12725
12726                 if (classoid < middle->classoid)
12727                         high = middle - 1;
12728                 else if (classoid > middle->classoid)
12729                         low = middle + 1;
12730                 else if (objoid < middle->objoid)
12731                         high = middle - 1;
12732                 else if (objoid > middle->objoid)
12733                         low = middle + 1;
12734                 else
12735                         break;                          /* found a match */
12736         }
12737
12738         if (low > high)                         /* no matches */
12739         {
12740                 *items = NULL;
12741                 return 0;
12742         }
12743
12744         /*
12745          * Now determine how many items match the object.  The search loop
12746          * invariant still holds: only items between low and high inclusive could
12747          * match.
12748          */
12749         nmatch = 1;
12750         while (middle > low)
12751         {
12752                 if (classoid != middle[-1].classoid ||
12753                         objoid != middle[-1].objoid)
12754                         break;
12755                 middle--;
12756                 nmatch++;
12757         }
12758
12759         *items = middle;
12760
12761         middle += nmatch;
12762         while (middle <= high)
12763         {
12764                 if (classoid != middle->classoid ||
12765                         objoid != middle->objoid)
12766                         break;
12767                 middle++;
12768                 nmatch++;
12769         }
12770
12771         return nmatch;
12772 }
12773
12774 /*
12775  * collectSecLabels
12776  *
12777  * Construct a table of all security labels available for database objects.
12778  * It's much faster to pull them all at once.
12779  *
12780  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12781  */
12782 static int
12783 collectSecLabels(Archive *fout, SecLabelItem **items)
12784 {
12785         PGresult   *res;
12786         PQExpBuffer query;
12787         int                     i_label;
12788         int                     i_provider;
12789         int                     i_classoid;
12790         int                     i_objoid;
12791         int                     i_objsubid;
12792         int                     ntups;
12793         int                     i;
12794         SecLabelItem *labels;
12795
12796         query = createPQExpBuffer();
12797
12798         appendPQExpBuffer(query,
12799                                           "SELECT label, provider, classoid, objoid, objsubid "
12800                                           "FROM pg_catalog.pg_seclabel "
12801                                           "ORDER BY classoid, objoid, objsubid");
12802
12803         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12804
12805         /* Construct lookup table containing OIDs in numeric form */
12806         i_label = PQfnumber(res, "label");
12807         i_provider = PQfnumber(res, "provider");
12808         i_classoid = PQfnumber(res, "classoid");
12809         i_objoid = PQfnumber(res, "objoid");
12810         i_objsubid = PQfnumber(res, "objsubid");
12811
12812         ntups = PQntuples(res);
12813
12814         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12815
12816         for (i = 0; i < ntups; i++)
12817         {
12818                 labels[i].label = PQgetvalue(res, i, i_label);
12819                 labels[i].provider = PQgetvalue(res, i, i_provider);
12820                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12821                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12822                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12823         }
12824
12825         /* Do NOT free the PGresult since we are keeping pointers into it */
12826         destroyPQExpBuffer(query);
12827
12828         *items = labels;
12829         return ntups;
12830 }
12831
12832 /*
12833  * dumpTable
12834  *        write out to fout the declarations (not data) of a user-defined table
12835  */
12836 static void
12837 dumpTable(Archive *fout, TableInfo *tbinfo)
12838 {
12839         if (tbinfo->dobj.dump && !dataOnly)
12840         {
12841                 char       *namecopy;
12842
12843                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12844                         dumpSequence(fout, tbinfo);
12845                 else
12846                         dumpTableSchema(fout, tbinfo);
12847
12848                 /* Handle the ACL here */
12849                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12850                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12851                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12852                                 "TABLE",
12853                                 namecopy, NULL, tbinfo->dobj.name,
12854                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12855                                 tbinfo->relacl);
12856
12857                 /*
12858                  * Handle column ACLs, if any.  Note: we pull these with a separate
12859                  * query rather than trying to fetch them during getTableAttrs, so
12860                  * that we won't miss ACLs on system columns.
12861                  */
12862                 if (fout->remoteVersion >= 80400)
12863                 {
12864                         PQExpBuffer query = createPQExpBuffer();
12865                         PGresult   *res;
12866                         int                     i;
12867
12868                         appendPQExpBuffer(query,
12869                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12870                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12871                                                           "ORDER BY attnum",
12872                                                           tbinfo->dobj.catId.oid);
12873                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12874
12875                         for (i = 0; i < PQntuples(res); i++)
12876                         {
12877                                 char       *attname = PQgetvalue(res, i, 0);
12878                                 char       *attacl = PQgetvalue(res, i, 1);
12879                                 char       *attnamecopy;
12880                                 char       *acltag;
12881
12882                                 attnamecopy = pg_strdup(fmtId(attname));
12883                                 acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
12884                                 /* Column's GRANT type is always TABLE */
12885                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12886                                                 namecopy, attnamecopy, acltag,
12887                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12888                                                 attacl);
12889                                 free(attnamecopy);
12890                                 free(acltag);
12891                         }
12892                         PQclear(res);
12893                         destroyPQExpBuffer(query);
12894                 }
12895
12896                 free(namecopy);
12897         }
12898 }
12899
12900 /*
12901  * Create the AS clause for a view or materialized view. The semicolon is
12902  * stripped because a materialized view must add a WITH NO DATA clause.
12903  *
12904  * This returns a new buffer which must be freed by the caller.
12905  */
12906 static PQExpBuffer
12907 createViewAsClause(Archive *fout, TableInfo *tbinfo)
12908 {
12909         PQExpBuffer query = createPQExpBuffer();
12910         PQExpBuffer result = createPQExpBuffer();
12911         PGresult   *res;
12912         int                     len;
12913
12914         /* Fetch the view definition */
12915         if (fout->remoteVersion >= 70300)
12916         {
12917                 /* Beginning in 7.3, viewname is not unique; rely on OID */
12918                 appendPQExpBuffer(query,
12919                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12920                                                   tbinfo->dobj.catId.oid);
12921         }
12922         else
12923         {
12924                 appendPQExpBuffer(query, "SELECT definition AS viewdef "
12925                                                   "FROM pg_views WHERE viewname = ");
12926                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12927         }
12928
12929         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12930
12931         if (PQntuples(res) != 1)
12932         {
12933                 if (PQntuples(res) < 1)
12934                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12935                                                   tbinfo->dobj.name);
12936                 else
12937                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12938                                                   tbinfo->dobj.name);
12939         }
12940
12941         len = PQgetlength(res, 0, 0);
12942
12943         if (len == 0)
12944                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12945                                           tbinfo->dobj.name);
12946
12947         /* Strip off the trailing semicolon so that other things may follow. */
12948         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
12949         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
12950
12951         PQclear(res);
12952         destroyPQExpBuffer(query);
12953
12954         return result;
12955 }
12956
12957 /*
12958  * dumpTableSchema
12959  *        write the declaration (not data) of one user-defined table or view
12960  */
12961 static void
12962 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12963 {
12964         PQExpBuffer q = createPQExpBuffer();
12965         PQExpBuffer delq = createPQExpBuffer();
12966         PQExpBuffer labelq = createPQExpBuffer();
12967         int                     numParents;
12968         TableInfo **parents;
12969         int                     actual_atts;    /* number of attrs in this CREATE statement */
12970         const char *reltypename;
12971         char       *storage;
12972         char       *srvname;
12973         char       *ftoptions;
12974         int                     j,
12975                                 k;
12976
12977         /* Make sure we are in proper schema */
12978         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12979
12980         if (binary_upgrade)
12981                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12982                                                                                                 tbinfo->dobj.catId.oid);
12983
12984         /* Is it a table or a view? */
12985         if (tbinfo->relkind == RELKIND_VIEW)
12986         {
12987                 PQExpBuffer result;
12988
12989                 reltypename = "VIEW";
12990
12991                 /*
12992                  * DROP must be fully qualified in case same name appears in
12993                  * pg_catalog
12994                  */
12995                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12996                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12997                 appendPQExpBuffer(delq, "%s;\n",
12998                                                   fmtId(tbinfo->dobj.name));
12999
13000                 if (binary_upgrade)
13001                         binary_upgrade_set_pg_class_oids(fout, q,
13002                                                                                          tbinfo->dobj.catId.oid, false);
13003
13004                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
13005                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13006                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
13007                 result = createViewAsClause(fout, tbinfo);
13008                 appendPQExpBuffer(q, " AS\n%s", result->data);
13009                 destroyPQExpBuffer(result);
13010
13011                 if (tbinfo->checkoption != NULL)
13012                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
13013                 appendPQExpBuffer(q, ";\n");
13014
13015                 appendPQExpBuffer(labelq, "VIEW %s",
13016                                                   fmtId(tbinfo->dobj.name));
13017         }
13018         else
13019         {
13020                 switch (tbinfo->relkind)
13021                 {
13022                         case (RELKIND_FOREIGN_TABLE):
13023                                 {
13024                                         PQExpBuffer query = createPQExpBuffer();
13025                                         PGresult   *res;
13026                                         int                     i_srvname;
13027                                         int                     i_ftoptions;
13028
13029                                         reltypename = "FOREIGN TABLE";
13030
13031                                         /* retrieve name of foreign server and generic options */
13032                                         appendPQExpBuffer(query,
13033                                                                           "SELECT fs.srvname, "
13034                                                                           "pg_catalog.array_to_string(ARRAY("
13035                                                          "SELECT pg_catalog.quote_ident(option_name) || "
13036                                                          "' ' || pg_catalog.quote_literal(option_value) "
13037                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
13038                                                                           "ORDER BY option_name"
13039                                                                           "), E',\n    ') AS ftoptions "
13040                                                                           "FROM pg_catalog.pg_foreign_table ft "
13041                                                                           "JOIN pg_catalog.pg_foreign_server fs "
13042                                                                           "ON (fs.oid = ft.ftserver) "
13043                                                                           "WHERE ft.ftrelid = '%u'",
13044                                                                           tbinfo->dobj.catId.oid);
13045                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13046                                         i_srvname = PQfnumber(res, "srvname");
13047                                         i_ftoptions = PQfnumber(res, "ftoptions");
13048                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
13049                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
13050                                         PQclear(res);
13051                                         destroyPQExpBuffer(query);
13052                                         break;
13053                                 }
13054                         case (RELKIND_MATVIEW):
13055                                 reltypename = "MATERIALIZED VIEW";
13056                                 srvname = NULL;
13057                                 ftoptions = NULL;
13058                                 break;
13059                         default:
13060                                 reltypename = "TABLE";
13061                                 srvname = NULL;
13062                                 ftoptions = NULL;
13063                 }
13064
13065                 numParents = tbinfo->numParents;
13066                 parents = tbinfo->parents;
13067
13068                 /*
13069                  * DROP must be fully qualified in case same name appears in
13070                  * pg_catalog
13071                  */
13072                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
13073                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13074                 appendPQExpBuffer(delq, "%s;\n",
13075                                                   fmtId(tbinfo->dobj.name));
13076
13077                 appendPQExpBuffer(labelq, "%s %s", reltypename,
13078                                                   fmtId(tbinfo->dobj.name));
13079
13080                 if (binary_upgrade)
13081                         binary_upgrade_set_pg_class_oids(fout, q,
13082                                                                                          tbinfo->dobj.catId.oid, false);
13083
13084                 appendPQExpBuffer(q, "CREATE %s%s %s",
13085                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
13086                                                   "UNLOGGED " : "",
13087                                                   reltypename,
13088                                                   fmtId(tbinfo->dobj.name));
13089
13090                 /*
13091                  * Attach to type, if reloftype; except in case of a binary upgrade,
13092                  * we dump the table normally and attach it to the type afterward.
13093                  */
13094                 if (tbinfo->reloftype && !binary_upgrade)
13095                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
13096
13097                 if (tbinfo->relkind != RELKIND_MATVIEW)
13098                 {
13099                         /* Dump the attributes */
13100                         actual_atts = 0;
13101                         for (j = 0; j < tbinfo->numatts; j++)
13102                         {
13103                                 /*
13104                                  * Normally, dump if it's locally defined in this table, and
13105                                  * not dropped.  But for binary upgrade, we'll dump all the
13106                                  * columns, and then fix up the dropped and nonlocal cases
13107                                  * below.
13108                                  */
13109                                 if (shouldPrintColumn(tbinfo, j))
13110                                 {
13111                                         /*
13112                                          * Default value --- suppress if to be printed separately.
13113                                          */
13114                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
13115                                                                                          !tbinfo->attrdefs[j]->separate);
13116
13117                                         /*
13118                                          * Not Null constraint --- suppress if inherited, except
13119                                          * in binary-upgrade case where that won't work.
13120                                          */
13121                                         bool            has_notnull = (tbinfo->notnull[j] &&
13122                                                                                            (!tbinfo->inhNotNull[j] ||
13123                                                                                                 binary_upgrade));
13124
13125                                         /* Skip column if fully defined by reloftype */
13126                                         if (tbinfo->reloftype &&
13127                                                 !has_default && !has_notnull && !binary_upgrade)
13128                                                 continue;
13129
13130                                         /* Format properly if not first attr */
13131                                         if (actual_atts == 0)
13132                                                 appendPQExpBuffer(q, " (");
13133                                         else
13134                                                 appendPQExpBuffer(q, ",");
13135                                         appendPQExpBuffer(q, "\n    ");
13136                                         actual_atts++;
13137
13138                                         /* Attribute name */
13139                                         appendPQExpBuffer(q, "%s",
13140                                                                           fmtId(tbinfo->attnames[j]));
13141
13142                                         if (tbinfo->attisdropped[j])
13143                                         {
13144                                                 /*
13145                                                  * ALTER TABLE DROP COLUMN clears
13146                                                  * pg_attribute.atttypid, so we will not have gotten a
13147                                                  * valid type name; insert INTEGER as a stopgap. We'll
13148                                                  * clean things up later.
13149                                                  */
13150                                                 appendPQExpBuffer(q, " INTEGER /* dummy */");
13151                                                 /* Skip all the rest, too */
13152                                                 continue;
13153                                         }
13154
13155                                         /* Attribute type */
13156                                         if (tbinfo->reloftype && !binary_upgrade)
13157                                         {
13158                                                 appendPQExpBuffer(q, " WITH OPTIONS");
13159                                         }
13160                                         else if (fout->remoteVersion >= 70100)
13161                                         {
13162                                                 appendPQExpBuffer(q, " %s",
13163                                                                                   tbinfo->atttypnames[j]);
13164                                         }
13165                                         else
13166                                         {
13167                                                 /* If no format_type, fake it */
13168                                                 appendPQExpBuffer(q, " %s",
13169                                                                                   myFormatType(tbinfo->atttypnames[j],
13170                                                                                                            tbinfo->atttypmod[j]));
13171                                         }
13172
13173                                         /* Add collation if not default for the type */
13174                                         if (OidIsValid(tbinfo->attcollation[j]))
13175                                         {
13176                                                 CollInfo   *coll;
13177
13178                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
13179                                                 if (coll)
13180                                                 {
13181                                                         /* always schema-qualify, don't try to be smart */
13182                                                         appendPQExpBuffer(q, " COLLATE %s.",
13183                                                                          fmtId(coll->dobj.namespace->dobj.name));
13184                                                         appendPQExpBuffer(q, "%s",
13185                                                                                           fmtId(coll->dobj.name));
13186                                                 }
13187                                         }
13188
13189                                         if (has_default)
13190                                                 appendPQExpBuffer(q, " DEFAULT %s",
13191                                                                                   tbinfo->attrdefs[j]->adef_expr);
13192
13193                                         if (has_notnull)
13194                                                 appendPQExpBuffer(q, " NOT NULL");
13195                                 }
13196                         }
13197
13198                         /*
13199                          * Add non-inherited CHECK constraints, if any.
13200                          */
13201                         for (j = 0; j < tbinfo->ncheck; j++)
13202                         {
13203                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13204
13205                                 if (constr->separate || !constr->conislocal)
13206                                         continue;
13207
13208                                 if (actual_atts == 0)
13209                                         appendPQExpBuffer(q, " (\n    ");
13210                                 else
13211                                         appendPQExpBuffer(q, ",\n    ");
13212
13213                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13214                                                                   fmtId(constr->dobj.name));
13215                                 appendPQExpBuffer(q, "%s", constr->condef);
13216
13217                                 actual_atts++;
13218                         }
13219
13220                         if (actual_atts)
13221                                 appendPQExpBuffer(q, "\n)");
13222                         else if (!(tbinfo->reloftype && !binary_upgrade))
13223                         {
13224                                 /*
13225                                  * We must have a parenthesized attribute list, even though
13226                                  * empty, when not using the OF TYPE syntax.
13227                                  */
13228                                 appendPQExpBuffer(q, " (\n)");
13229                         }
13230
13231                         if (numParents > 0 && !binary_upgrade)
13232                         {
13233                                 appendPQExpBuffer(q, "\nINHERITS (");
13234                                 for (k = 0; k < numParents; k++)
13235                                 {
13236                                         TableInfo  *parentRel = parents[k];
13237
13238                                         if (k > 0)
13239                                                 appendPQExpBuffer(q, ", ");
13240                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13241                                                 appendPQExpBuffer(q, "%s.",
13242                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13243                                         appendPQExpBuffer(q, "%s",
13244                                                                           fmtId(parentRel->dobj.name));
13245                                 }
13246                                 appendPQExpBuffer(q, ")");
13247                         }
13248
13249                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13250                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13251                 }
13252
13253                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13254                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13255                 {
13256                         bool            addcomma = false;
13257
13258                         appendPQExpBuffer(q, "\nWITH (");
13259                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13260                         {
13261                                 addcomma = true;
13262                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
13263                         }
13264                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13265                         {
13266                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13267                                                                   tbinfo->toast_reloptions);
13268                         }
13269                         appendPQExpBuffer(q, ")");
13270                 }
13271
13272                 /* Dump generic options if any */
13273                 if (ftoptions && ftoptions[0])
13274                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13275
13276                 /*
13277                  * For materialized views, create the AS clause just like a view. At
13278                  * this point, we always mark the view as not populated.
13279                  */
13280                 if (tbinfo->relkind == RELKIND_MATVIEW)
13281                 {
13282                         PQExpBuffer result;
13283
13284                         result = createViewAsClause(fout, tbinfo);
13285                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13286                                                           result->data);
13287                         destroyPQExpBuffer(result);
13288                 }
13289                 else
13290                         appendPQExpBuffer(q, ";\n");
13291
13292                 /*
13293                  * To create binary-compatible heap files, we have to ensure the same
13294                  * physical column order, including dropped columns, as in the
13295                  * original.  Therefore, we create dropped columns above and drop them
13296                  * here, also updating their attlen/attalign values so that the
13297                  * dropped column can be skipped properly.      (We do not bother with
13298                  * restoring the original attbyval setting.)  Also, inheritance
13299                  * relationships are set up by doing ALTER INHERIT rather than using
13300                  * an INHERITS clause --- the latter would possibly mess up the column
13301                  * order.  That also means we have to take care about setting
13302                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13303                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13304                  */
13305                 if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
13306                                                            tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
13307                 {
13308                         for (j = 0; j < tbinfo->numatts; j++)
13309                         {
13310                                 if (tbinfo->attisdropped[j])
13311                                 {
13312                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
13313                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13314                                                                           "SET attlen = %d, "
13315                                                                           "attalign = '%c', attbyval = false\n"
13316                                                                           "WHERE attname = ",
13317                                                                           tbinfo->attlen[j],
13318                                                                           tbinfo->attalign[j]);
13319                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13320                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13321                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13322                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13323
13324                                         if (tbinfo->relkind == RELKIND_RELATION)
13325                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13326                                                                                   fmtId(tbinfo->dobj.name));
13327                                         else
13328                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13329                                                                                   fmtId(tbinfo->dobj.name));
13330
13331                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13332                                                                           fmtId(tbinfo->attnames[j]));
13333                                 }
13334                                 else if (!tbinfo->attislocal[j])
13335                                 {
13336                                         Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
13337                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
13338                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13339                                                                           "SET attislocal = false\n"
13340                                                                           "WHERE attname = ");
13341                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13342                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13343                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13344                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13345                                 }
13346                         }
13347
13348                         for (k = 0; k < tbinfo->ncheck; k++)
13349                         {
13350                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13351
13352                                 if (constr->separate || constr->conislocal)
13353                                         continue;
13354
13355                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13356                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13357                                                                   fmtId(tbinfo->dobj.name));
13358                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13359                                                                   fmtId(constr->dobj.name));
13360                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13361                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
13362                                                                   "SET conislocal = false\n"
13363                                                                   "WHERE contype = 'c' AND conname = ");
13364                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13365                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
13366                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13367                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13368                         }
13369
13370                         if (numParents > 0)
13371                         {
13372                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13373                                 for (k = 0; k < numParents; k++)
13374                                 {
13375                                         TableInfo  *parentRel = parents[k];
13376
13377                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13378                                                                           fmtId(tbinfo->dobj.name));
13379                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13380                                                 appendPQExpBuffer(q, "%s.",
13381                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13382                                         appendPQExpBuffer(q, "%s;\n",
13383                                                                           fmtId(parentRel->dobj.name));
13384                                 }
13385                         }
13386
13387                         if (tbinfo->reloftype)
13388                         {
13389                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13390                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13391                                                                   fmtId(tbinfo->dobj.name),
13392                                                                   tbinfo->reloftype);
13393                         }
13394
13395                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13396                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13397                                                           "SET relfrozenxid = '%u'\n"
13398                                                           "WHERE oid = ",
13399                                                           tbinfo->frozenxid);
13400                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13401                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13402
13403                         if (tbinfo->toast_oid)
13404                         {
13405                                 /* We preserve the toast oids, so we can use it during restore */
13406                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13407                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13408                                                                   "SET relfrozenxid = '%u'\n"
13409                                                                   "WHERE oid = '%u';\n",
13410                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13411                         }
13412                 }
13413
13414                 /*
13415                  * In binary_upgrade mode, restore matviews' populated status by
13416                  * poking pg_class directly.  This is pretty ugly, but we can't use
13417                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
13418                  * matview is not populated even though this matview is.
13419                  */
13420                 if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
13421                         tbinfo->relispopulated)
13422                 {
13423                         appendPQExpBuffer(q, "\n-- For binary upgrade, mark materialized view as populated\n");
13424                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13425                                                           "SET relispopulated = 't'\n"
13426                                                           "WHERE oid = ");
13427                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13428                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13429                 }
13430
13431                 /*
13432                  * Dump additional per-column properties that we can't handle in the
13433                  * main CREATE TABLE command.
13434                  */
13435                 for (j = 0; j < tbinfo->numatts; j++)
13436                 {
13437                         /* None of this applies to dropped columns */
13438                         if (tbinfo->attisdropped[j])
13439                                 continue;
13440
13441                         /*
13442                          * If we didn't dump the column definition explicitly above, and
13443                          * it is NOT NULL and did not inherit that property from a parent,
13444                          * we have to mark it separately.
13445                          */
13446                         if (!shouldPrintColumn(tbinfo, j) &&
13447                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13448                         {
13449                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13450                                                                   fmtId(tbinfo->dobj.name));
13451                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13452                                                                   fmtId(tbinfo->attnames[j]));
13453                         }
13454
13455                         /*
13456                          * Dump per-column statistics information. We only issue an ALTER
13457                          * TABLE statement if the attstattarget entry for this column is
13458                          * non-negative (i.e. it's not the default value)
13459                          */
13460                         if (tbinfo->attstattarget[j] >= 0)
13461                         {
13462                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13463                                                                   fmtId(tbinfo->dobj.name));
13464                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13465                                                                   fmtId(tbinfo->attnames[j]));
13466                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13467                                                                   tbinfo->attstattarget[j]);
13468                         }
13469
13470                         /*
13471                          * Dump per-column storage information.  The statement is only
13472                          * dumped if the storage has been changed from the type's default.
13473                          */
13474                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13475                         {
13476                                 switch (tbinfo->attstorage[j])
13477                                 {
13478                                         case 'p':
13479                                                 storage = "PLAIN";
13480                                                 break;
13481                                         case 'e':
13482                                                 storage = "EXTERNAL";
13483                                                 break;
13484                                         case 'm':
13485                                                 storage = "MAIN";
13486                                                 break;
13487                                         case 'x':
13488                                                 storage = "EXTENDED";
13489                                                 break;
13490                                         default:
13491                                                 storage = NULL;
13492                                 }
13493
13494                                 /*
13495                                  * Only dump the statement if it's a storage type we recognize
13496                                  */
13497                                 if (storage != NULL)
13498                                 {
13499                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13500                                                                           fmtId(tbinfo->dobj.name));
13501                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
13502                                                                           fmtId(tbinfo->attnames[j]));
13503                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
13504                                                                           storage);
13505                                 }
13506                         }
13507
13508                         /*
13509                          * Dump per-column attributes.
13510                          */
13511                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13512                         {
13513                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13514                                                                   fmtId(tbinfo->dobj.name));
13515                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13516                                                                   fmtId(tbinfo->attnames[j]));
13517                                 appendPQExpBuffer(q, "SET (%s);\n",
13518                                                                   tbinfo->attoptions[j]);
13519                         }
13520
13521                         /*
13522                          * Dump per-column fdw options.
13523                          */
13524                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13525                                 tbinfo->attfdwoptions[j] &&
13526                                 tbinfo->attfdwoptions[j][0] != '\0')
13527                         {
13528                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13529                                                                   fmtId(tbinfo->dobj.name));
13530                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13531                                                                   fmtId(tbinfo->attnames[j]));
13532                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13533                                                                   tbinfo->attfdwoptions[j]);
13534                         }
13535                 }
13536         }
13537
13538         /*
13539          * dump properties we only have ALTER TABLE syntax for
13540          */
13541         if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) &&
13542                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
13543         {
13544                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
13545                 {
13546                         /* nothing to do, will be set when the index is dumped */
13547                 }
13548                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
13549                 {
13550                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
13551                                                           fmtId(tbinfo->dobj.name));
13552                 }
13553                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
13554                 {
13555                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
13556                                                           fmtId(tbinfo->dobj.name));
13557                 }
13558         }
13559
13560         if (binary_upgrade)
13561                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13562
13563         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13564                                  tbinfo->dobj.name,
13565                                  tbinfo->dobj.namespace->dobj.name,
13566                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13567                                  tbinfo->rolname,
13568                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13569                                  reltypename, SECTION_PRE_DATA,
13570                                  q->data, delq->data, NULL,
13571                                  NULL, 0,
13572                                  NULL, NULL);
13573
13574
13575         /* Dump Table Comments */
13576         dumpTableComment(fout, tbinfo, reltypename);
13577
13578         /* Dump Table Security Labels */
13579         dumpTableSecLabel(fout, tbinfo, reltypename);
13580
13581         /* Dump comments on inlined table constraints */
13582         for (j = 0; j < tbinfo->ncheck; j++)
13583         {
13584                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13585
13586                 if (constr->separate || !constr->conislocal)
13587                         continue;
13588
13589                 dumpTableConstraintComment(fout, constr);
13590         }
13591
13592         destroyPQExpBuffer(q);
13593         destroyPQExpBuffer(delq);
13594         destroyPQExpBuffer(labelq);
13595 }
13596
13597 /*
13598  * dumpAttrDef --- dump an attribute's default-value declaration
13599  */
13600 static void
13601 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13602 {
13603         TableInfo  *tbinfo = adinfo->adtable;
13604         int                     adnum = adinfo->adnum;
13605         PQExpBuffer q;
13606         PQExpBuffer delq;
13607
13608         /* Skip if table definition not to be dumped */
13609         if (!tbinfo->dobj.dump || dataOnly)
13610                 return;
13611
13612         /* Skip if not "separate"; it was dumped in the table's definition */
13613         if (!adinfo->separate)
13614                 return;
13615
13616         q = createPQExpBuffer();
13617         delq = createPQExpBuffer();
13618
13619         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13620                                           fmtId(tbinfo->dobj.name));
13621         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13622                                           fmtId(tbinfo->attnames[adnum - 1]),
13623                                           adinfo->adef_expr);
13624
13625         /*
13626          * DROP must be fully qualified in case same name appears in pg_catalog
13627          */
13628         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13629                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13630         appendPQExpBuffer(delq, "%s ",
13631                                           fmtId(tbinfo->dobj.name));
13632         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13633                                           fmtId(tbinfo->attnames[adnum - 1]));
13634
13635         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13636                                  tbinfo->attnames[adnum - 1],
13637                                  tbinfo->dobj.namespace->dobj.name,
13638                                  NULL,
13639                                  tbinfo->rolname,
13640                                  false, "DEFAULT", SECTION_PRE_DATA,
13641                                  q->data, delq->data, NULL,
13642                                  NULL, 0,
13643                                  NULL, NULL);
13644
13645         destroyPQExpBuffer(q);
13646         destroyPQExpBuffer(delq);
13647 }
13648
13649 /*
13650  * getAttrName: extract the correct name for an attribute
13651  *
13652  * The array tblInfo->attnames[] only provides names of user attributes;
13653  * if a system attribute number is supplied, we have to fake it.
13654  * We also do a little bit of bounds checking for safety's sake.
13655  */
13656 static const char *
13657 getAttrName(int attrnum, TableInfo *tblInfo)
13658 {
13659         if (attrnum > 0 && attrnum <= tblInfo->numatts)
13660                 return tblInfo->attnames[attrnum - 1];
13661         switch (attrnum)
13662         {
13663                 case SelfItemPointerAttributeNumber:
13664                         return "ctid";
13665                 case ObjectIdAttributeNumber:
13666                         return "oid";
13667                 case MinTransactionIdAttributeNumber:
13668                         return "xmin";
13669                 case MinCommandIdAttributeNumber:
13670                         return "cmin";
13671                 case MaxTransactionIdAttributeNumber:
13672                         return "xmax";
13673                 case MaxCommandIdAttributeNumber:
13674                         return "cmax";
13675                 case TableOidAttributeNumber:
13676                         return "tableoid";
13677         }
13678         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13679                                   attrnum, tblInfo->dobj.name);
13680         return NULL;                            /* keep compiler quiet */
13681 }
13682
13683 /*
13684  * dumpIndex
13685  *        write out to fout a user-defined index
13686  */
13687 static void
13688 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13689 {
13690         TableInfo  *tbinfo = indxinfo->indextable;
13691         bool            is_constraint = (indxinfo->indexconstraint != 0);
13692         PQExpBuffer q;
13693         PQExpBuffer delq;
13694         PQExpBuffer labelq;
13695
13696         if (dataOnly)
13697                 return;
13698
13699         q = createPQExpBuffer();
13700         delq = createPQExpBuffer();
13701         labelq = createPQExpBuffer();
13702
13703         appendPQExpBuffer(labelq, "INDEX %s",
13704                                           fmtId(indxinfo->dobj.name));
13705
13706         /*
13707          * If there's an associated constraint, don't dump the index per se, but
13708          * do dump any comment for it.  (This is safe because dependency ordering
13709          * will have ensured the constraint is emitted first.)  Note that the
13710          * emitted comment has to be shown as depending on the constraint, not
13711          * the index, in such cases.
13712          */
13713         if (!is_constraint)
13714         {
13715                 if (binary_upgrade)
13716                         binary_upgrade_set_pg_class_oids(fout, q,
13717                                                                                          indxinfo->dobj.catId.oid, true);
13718
13719                 /* Plain secondary index */
13720                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13721
13722                 /* If the index is clustered, we need to record that. */
13723                 if (indxinfo->indisclustered)
13724                 {
13725                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13726                                                           fmtId(tbinfo->dobj.name));
13727                         appendPQExpBuffer(q, " ON %s;\n",
13728                                                           fmtId(indxinfo->dobj.name));
13729                 }
13730
13731                 /* If the index is clustered, we need to record that. */
13732                 if (indxinfo->indisreplident)
13733                 {
13734                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
13735                                                           fmtId(tbinfo->dobj.name));
13736                         appendPQExpBuffer(q, " INDEX %s;\n",
13737                                                           fmtId(indxinfo->dobj.name));
13738                 }
13739
13740                 /*
13741                  * DROP must be fully qualified in case same name appears in
13742                  * pg_catalog
13743                  */
13744                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13745                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13746                 appendPQExpBuffer(delq, "%s;\n",
13747                                                   fmtId(indxinfo->dobj.name));
13748
13749                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13750                                          indxinfo->dobj.name,
13751                                          tbinfo->dobj.namespace->dobj.name,
13752                                          indxinfo->tablespace,
13753                                          tbinfo->rolname, false,
13754                                          "INDEX", SECTION_POST_DATA,
13755                                          q->data, delq->data, NULL,
13756                                          NULL, 0,
13757                                          NULL, NULL);
13758         }
13759
13760         /* Dump Index Comments */
13761         dumpComment(fout, labelq->data,
13762                                 tbinfo->dobj.namespace->dobj.name,
13763                                 tbinfo->rolname,
13764                                 indxinfo->dobj.catId, 0,
13765                                 is_constraint ? indxinfo->indexconstraint :
13766                                 indxinfo->dobj.dumpId);
13767
13768         destroyPQExpBuffer(q);
13769         destroyPQExpBuffer(delq);
13770         destroyPQExpBuffer(labelq);
13771 }
13772
13773 /*
13774  * dumpConstraint
13775  *        write out to fout a user-defined constraint
13776  */
13777 static void
13778 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13779 {
13780         TableInfo  *tbinfo = coninfo->contable;
13781         PQExpBuffer q;
13782         PQExpBuffer delq;
13783
13784         /* Skip if not to be dumped */
13785         if (!coninfo->dobj.dump || dataOnly)
13786                 return;
13787
13788         q = createPQExpBuffer();
13789         delq = createPQExpBuffer();
13790
13791         if (coninfo->contype == 'p' ||
13792                 coninfo->contype == 'u' ||
13793                 coninfo->contype == 'x')
13794         {
13795                 /* Index-related constraint */
13796                 IndxInfo   *indxinfo;
13797                 int                     k;
13798
13799                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13800
13801                 if (indxinfo == NULL)
13802                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13803                                                   coninfo->dobj.name);
13804
13805                 if (binary_upgrade)
13806                         binary_upgrade_set_pg_class_oids(fout, q,
13807                                                                                          indxinfo->dobj.catId.oid, true);
13808
13809                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13810                                                   fmtId(tbinfo->dobj.name));
13811                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13812                                                   fmtId(coninfo->dobj.name));
13813
13814                 if (coninfo->condef)
13815                 {
13816                         /* pg_get_constraintdef should have provided everything */
13817                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13818                 }
13819                 else
13820                 {
13821                         appendPQExpBuffer(q, "%s (",
13822                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13823                         for (k = 0; k < indxinfo->indnkeys; k++)
13824                         {
13825                                 int                     indkey = (int) indxinfo->indkeys[k];
13826                                 const char *attname;
13827
13828                                 if (indkey == InvalidAttrNumber)
13829                                         break;
13830                                 attname = getAttrName(indkey, tbinfo);
13831
13832                                 appendPQExpBuffer(q, "%s%s",
13833                                                                   (k == 0) ? "" : ", ",
13834                                                                   fmtId(attname));
13835                         }
13836
13837                         appendPQExpBuffer(q, ")");
13838
13839                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13840                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13841
13842                         if (coninfo->condeferrable)
13843                         {
13844                                 appendPQExpBuffer(q, " DEFERRABLE");
13845                                 if (coninfo->condeferred)
13846                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13847                         }
13848
13849                         appendPQExpBuffer(q, ";\n");
13850                 }
13851
13852                 /* If the index is clustered, we need to record that. */
13853                 if (indxinfo->indisclustered)
13854                 {
13855                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13856                                                           fmtId(tbinfo->dobj.name));
13857                         appendPQExpBuffer(q, " ON %s;\n",
13858                                                           fmtId(indxinfo->dobj.name));
13859                 }
13860
13861                 /*
13862                  * DROP must be fully qualified in case same name appears in
13863                  * pg_catalog
13864                  */
13865                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13866                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13867                 appendPQExpBuffer(delq, "%s ",
13868                                                   fmtId(tbinfo->dobj.name));
13869                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13870                                                   fmtId(coninfo->dobj.name));
13871
13872                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13873                                          coninfo->dobj.name,
13874                                          tbinfo->dobj.namespace->dobj.name,
13875                                          indxinfo->tablespace,
13876                                          tbinfo->rolname, false,
13877                                          "CONSTRAINT", SECTION_POST_DATA,
13878                                          q->data, delq->data, NULL,
13879                                          NULL, 0,
13880                                          NULL, NULL);
13881         }
13882         else if (coninfo->contype == 'f')
13883         {
13884                 /*
13885                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13886                  * current table data is not processed
13887                  */
13888                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13889                                                   fmtId(tbinfo->dobj.name));
13890                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13891                                                   fmtId(coninfo->dobj.name),
13892                                                   coninfo->condef);
13893
13894                 /*
13895                  * DROP must be fully qualified in case same name appears in
13896                  * pg_catalog
13897                  */
13898                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13899                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13900                 appendPQExpBuffer(delq, "%s ",
13901                                                   fmtId(tbinfo->dobj.name));
13902                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13903                                                   fmtId(coninfo->dobj.name));
13904
13905                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13906                                          coninfo->dobj.name,
13907                                          tbinfo->dobj.namespace->dobj.name,
13908                                          NULL,
13909                                          tbinfo->rolname, false,
13910                                          "FK CONSTRAINT", SECTION_POST_DATA,
13911                                          q->data, delq->data, NULL,
13912                                          NULL, 0,
13913                                          NULL, NULL);
13914         }
13915         else if (coninfo->contype == 'c' && tbinfo)
13916         {
13917                 /* CHECK constraint on a table */
13918
13919                 /* Ignore if not to be dumped separately */
13920                 if (coninfo->separate)
13921                 {
13922                         /* not ONLY since we want it to propagate to children */
13923                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13924                                                           fmtId(tbinfo->dobj.name));
13925                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13926                                                           fmtId(coninfo->dobj.name),
13927                                                           coninfo->condef);
13928
13929                         /*
13930                          * DROP must be fully qualified in case same name appears in
13931                          * pg_catalog
13932                          */
13933                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13934                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13935                         appendPQExpBuffer(delq, "%s ",
13936                                                           fmtId(tbinfo->dobj.name));
13937                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13938                                                           fmtId(coninfo->dobj.name));
13939
13940                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13941                                                  coninfo->dobj.name,
13942                                                  tbinfo->dobj.namespace->dobj.name,
13943                                                  NULL,
13944                                                  tbinfo->rolname, false,
13945                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13946                                                  q->data, delq->data, NULL,
13947                                                  NULL, 0,
13948                                                  NULL, NULL);
13949                 }
13950         }
13951         else if (coninfo->contype == 'c' && tbinfo == NULL)
13952         {
13953                 /* CHECK constraint on a domain */
13954                 TypeInfo   *tyinfo = coninfo->condomain;
13955
13956                 /* Ignore if not to be dumped separately */
13957                 if (coninfo->separate)
13958                 {
13959                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13960                                                           fmtId(tyinfo->dobj.name));
13961                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13962                                                           fmtId(coninfo->dobj.name),
13963                                                           coninfo->condef);
13964
13965                         /*
13966                          * DROP must be fully qualified in case same name appears in
13967                          * pg_catalog
13968                          */
13969                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13970                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13971                         appendPQExpBuffer(delq, "%s ",
13972                                                           fmtId(tyinfo->dobj.name));
13973                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13974                                                           fmtId(coninfo->dobj.name));
13975
13976                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13977                                                  coninfo->dobj.name,
13978                                                  tyinfo->dobj.namespace->dobj.name,
13979                                                  NULL,
13980                                                  tyinfo->rolname, false,
13981                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13982                                                  q->data, delq->data, NULL,
13983                                                  NULL, 0,
13984                                                  NULL, NULL);
13985                 }
13986         }
13987         else
13988         {
13989                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
13990                                           coninfo->contype);
13991         }
13992
13993         /* Dump Constraint Comments --- only works for table constraints */
13994         if (tbinfo && coninfo->separate)
13995                 dumpTableConstraintComment(fout, coninfo);
13996
13997         destroyPQExpBuffer(q);
13998         destroyPQExpBuffer(delq);
13999 }
14000
14001 /*
14002  * dumpTableConstraintComment --- dump a constraint's comment if any
14003  *
14004  * This is split out because we need the function in two different places
14005  * depending on whether the constraint is dumped as part of CREATE TABLE
14006  * or as a separate ALTER command.
14007  */
14008 static void
14009 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
14010 {
14011         TableInfo  *tbinfo = coninfo->contable;
14012         PQExpBuffer labelq = createPQExpBuffer();
14013
14014         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
14015                                           fmtId(coninfo->dobj.name));
14016         appendPQExpBuffer(labelq, "ON %s",
14017                                           fmtId(tbinfo->dobj.name));
14018         dumpComment(fout, labelq->data,
14019                                 tbinfo->dobj.namespace->dobj.name,
14020                                 tbinfo->rolname,
14021                                 coninfo->dobj.catId, 0,
14022                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
14023
14024         destroyPQExpBuffer(labelq);
14025 }
14026
14027 /*
14028  * findLastBuiltInOid -
14029  * find the last built in oid
14030  *
14031  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
14032  * pg_database entry for the current database
14033  */
14034 static Oid
14035 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
14036 {
14037         PGresult   *res;
14038         Oid                     last_oid;
14039         PQExpBuffer query = createPQExpBuffer();
14040
14041         resetPQExpBuffer(query);
14042         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
14043         appendStringLiteralAH(query, dbname, fout);
14044
14045         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14046         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
14047         PQclear(res);
14048         destroyPQExpBuffer(query);
14049         return last_oid;
14050 }
14051
14052 /*
14053  * findLastBuiltInOid -
14054  * find the last built in oid
14055  *
14056  * For 7.0, we do this by assuming that the last thing that initdb does is to
14057  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
14058  * initdb won't be changing anymore, it'll do.
14059  */
14060 static Oid
14061 findLastBuiltinOid_V70(Archive *fout)
14062 {
14063         PGresult   *res;
14064         int                     last_oid;
14065
14066         res = ExecuteSqlQueryForSingleRow(fout,
14067                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
14068         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
14069         PQclear(res);
14070         return last_oid;
14071 }
14072
14073 /*
14074  * dumpSequence
14075  *        write the declaration (not data) of one user-defined sequence
14076  */
14077 static void
14078 dumpSequence(Archive *fout, TableInfo *tbinfo)
14079 {
14080         PGresult   *res;
14081         char       *startv,
14082                            *incby,
14083                            *maxv = NULL,
14084                            *minv = NULL,
14085                            *cache;
14086         char            bufm[100],
14087                                 bufx[100];
14088         bool            cycled;
14089         PQExpBuffer query = createPQExpBuffer();
14090         PQExpBuffer delqry = createPQExpBuffer();
14091         PQExpBuffer labelq = createPQExpBuffer();
14092
14093         /* Make sure we are in proper schema */
14094         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14095
14096         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
14097         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
14098
14099         if (fout->remoteVersion >= 80400)
14100         {
14101                 appendPQExpBuffer(query,
14102                                                   "SELECT sequence_name, "
14103                                                   "start_value, increment_by, "
14104                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14105                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14106                                                   "     ELSE max_value "
14107                                                   "END AS max_value, "
14108                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14109                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14110                                                   "     ELSE min_value "
14111                                                   "END AS min_value, "
14112                                                   "cache_value, is_cycled FROM %s",
14113                                                   bufx, bufm,
14114                                                   fmtId(tbinfo->dobj.name));
14115         }
14116         else
14117         {
14118                 appendPQExpBuffer(query,
14119                                                   "SELECT sequence_name, "
14120                                                   "0 AS start_value, increment_by, "
14121                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14122                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14123                                                   "     ELSE max_value "
14124                                                   "END AS max_value, "
14125                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14126                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14127                                                   "     ELSE min_value "
14128                                                   "END AS min_value, "
14129                                                   "cache_value, is_cycled FROM %s",
14130                                                   bufx, bufm,
14131                                                   fmtId(tbinfo->dobj.name));
14132         }
14133
14134         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14135
14136         if (PQntuples(res) != 1)
14137         {
14138                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14139                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14140                                                                  PQntuples(res)),
14141                                   tbinfo->dobj.name, PQntuples(res));
14142                 exit_nicely(1);
14143         }
14144
14145         /* Disable this check: it fails if sequence has been renamed */
14146 #ifdef NOT_USED
14147         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
14148         {
14149                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
14150                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
14151                 exit_nicely(1);
14152         }
14153 #endif
14154
14155         startv = PQgetvalue(res, 0, 1);
14156         incby = PQgetvalue(res, 0, 2);
14157         if (!PQgetisnull(res, 0, 3))
14158                 maxv = PQgetvalue(res, 0, 3);
14159         if (!PQgetisnull(res, 0, 4))
14160                 minv = PQgetvalue(res, 0, 4);
14161         cache = PQgetvalue(res, 0, 5);
14162         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
14163
14164         /*
14165          * DROP must be fully qualified in case same name appears in pg_catalog
14166          */
14167         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
14168                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14169         appendPQExpBuffer(delqry, "%s;\n",
14170                                           fmtId(tbinfo->dobj.name));
14171
14172         resetPQExpBuffer(query);
14173
14174         if (binary_upgrade)
14175         {
14176                 binary_upgrade_set_pg_class_oids(fout, query,
14177                                                                                  tbinfo->dobj.catId.oid, false);
14178                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
14179                                                                                                 tbinfo->dobj.catId.oid);
14180         }
14181
14182         appendPQExpBuffer(query,
14183                                           "CREATE SEQUENCE %s\n",
14184                                           fmtId(tbinfo->dobj.name));
14185
14186         if (fout->remoteVersion >= 80400)
14187                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
14188
14189         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
14190
14191         if (minv)
14192                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
14193         else
14194                 appendPQExpBuffer(query, "    NO MINVALUE\n");
14195
14196         if (maxv)
14197                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
14198         else
14199                 appendPQExpBuffer(query, "    NO MAXVALUE\n");
14200
14201         appendPQExpBuffer(query,
14202                                           "    CACHE %s%s",
14203                                           cache, (cycled ? "\n    CYCLE" : ""));
14204
14205         appendPQExpBuffer(query, ";\n");
14206
14207         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
14208
14209         /* binary_upgrade:      no need to clear TOAST table oid */
14210
14211         if (binary_upgrade)
14212                 binary_upgrade_extension_member(query, &tbinfo->dobj,
14213                                                                                 labelq->data);
14214
14215         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14216                                  tbinfo->dobj.name,
14217                                  tbinfo->dobj.namespace->dobj.name,
14218                                  NULL,
14219                                  tbinfo->rolname,
14220                                  false, "SEQUENCE", SECTION_PRE_DATA,
14221                                  query->data, delqry->data, NULL,
14222                                  NULL, 0,
14223                                  NULL, NULL);
14224
14225         /*
14226          * If the sequence is owned by a table column, emit the ALTER for it as a
14227          * separate TOC entry immediately following the sequence's own entry. It's
14228          * OK to do this rather than using full sorting logic, because the
14229          * dependency that tells us it's owned will have forced the table to be
14230          * created first.  We can't just include the ALTER in the TOC entry
14231          * because it will fail if we haven't reassigned the sequence owner to
14232          * match the table's owner.
14233          *
14234          * We need not schema-qualify the table reference because both sequence
14235          * and table must be in the same schema.
14236          */
14237         if (OidIsValid(tbinfo->owning_tab))
14238         {
14239                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14240
14241                 if (owning_tab && owning_tab->dobj.dump)
14242                 {
14243                         resetPQExpBuffer(query);
14244                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14245                                                           fmtId(tbinfo->dobj.name));
14246                         appendPQExpBuffer(query, " OWNED BY %s",
14247                                                           fmtId(owning_tab->dobj.name));
14248                         appendPQExpBuffer(query, ".%s;\n",
14249                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14250
14251                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14252                                                  tbinfo->dobj.name,
14253                                                  tbinfo->dobj.namespace->dobj.name,
14254                                                  NULL,
14255                                                  tbinfo->rolname,
14256                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14257                                                  query->data, "", NULL,
14258                                                  &(tbinfo->dobj.dumpId), 1,
14259                                                  NULL, NULL);
14260                 }
14261         }
14262
14263         /* Dump Sequence Comments and Security Labels */
14264         dumpComment(fout, labelq->data,
14265                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14266                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14267         dumpSecLabel(fout, labelq->data,
14268                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14269                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14270
14271         PQclear(res);
14272
14273         destroyPQExpBuffer(query);
14274         destroyPQExpBuffer(delqry);
14275         destroyPQExpBuffer(labelq);
14276 }
14277
14278 /*
14279  * dumpSequenceData
14280  *        write the data of one user-defined sequence
14281  */
14282 static void
14283 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14284 {
14285         TableInfo  *tbinfo = tdinfo->tdtable;
14286         PGresult   *res;
14287         char       *last;
14288         bool            called;
14289         PQExpBuffer query = createPQExpBuffer();
14290
14291         /* Make sure we are in proper schema */
14292         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14293
14294         appendPQExpBuffer(query,
14295                                           "SELECT last_value, is_called FROM %s",
14296                                           fmtId(tbinfo->dobj.name));
14297
14298         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14299
14300         if (PQntuples(res) != 1)
14301         {
14302                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14303                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14304                                                                  PQntuples(res)),
14305                                   tbinfo->dobj.name, PQntuples(res));
14306                 exit_nicely(1);
14307         }
14308
14309         last = PQgetvalue(res, 0, 0);
14310         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14311
14312         resetPQExpBuffer(query);
14313         appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
14314         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14315         appendPQExpBuffer(query, ", %s, %s);\n",
14316                                           last, (called ? "true" : "false"));
14317
14318         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14319                                  tbinfo->dobj.name,
14320                                  tbinfo->dobj.namespace->dobj.name,
14321                                  NULL,
14322                                  tbinfo->rolname,
14323                                  false, "SEQUENCE SET", SECTION_DATA,
14324                                  query->data, "", NULL,
14325                                  &(tbinfo->dobj.dumpId), 1,
14326                                  NULL, NULL);
14327
14328         PQclear(res);
14329
14330         destroyPQExpBuffer(query);
14331 }
14332
14333 static void
14334 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14335 {
14336         TableInfo  *tbinfo = tginfo->tgtable;
14337         PQExpBuffer query;
14338         PQExpBuffer delqry;
14339         PQExpBuffer labelq;
14340         char       *tgargs;
14341         size_t          lentgargs;
14342         const char *p;
14343         int                     findx;
14344
14345         if (dataOnly)
14346                 return;
14347
14348         query = createPQExpBuffer();
14349         delqry = createPQExpBuffer();
14350         labelq = createPQExpBuffer();
14351
14352         /*
14353          * DROP must be fully qualified in case same name appears in pg_catalog
14354          */
14355         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14356                                           fmtId(tginfo->dobj.name));
14357         appendPQExpBuffer(delqry, "ON %s.",
14358                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14359         appendPQExpBuffer(delqry, "%s;\n",
14360                                           fmtId(tbinfo->dobj.name));
14361
14362         if (tginfo->tgdef)
14363         {
14364                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14365         }
14366         else
14367         {
14368                 if (tginfo->tgisconstraint)
14369                 {
14370                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
14371                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14372                 }
14373                 else
14374                 {
14375                         appendPQExpBuffer(query, "CREATE TRIGGER ");
14376                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14377                 }
14378                 appendPQExpBuffer(query, "\n    ");
14379
14380                 /* Trigger type */
14381                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14382                         appendPQExpBuffer(query, "BEFORE");
14383                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14384                         appendPQExpBuffer(query, "AFTER");
14385                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14386                         appendPQExpBuffer(query, "INSTEAD OF");
14387                 else
14388                 {
14389                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14390                         exit_nicely(1);
14391                 }
14392
14393                 findx = 0;
14394                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14395                 {
14396                         appendPQExpBuffer(query, " INSERT");
14397                         findx++;
14398                 }
14399                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14400                 {
14401                         if (findx > 0)
14402                                 appendPQExpBuffer(query, " OR DELETE");
14403                         else
14404                                 appendPQExpBuffer(query, " DELETE");
14405                         findx++;
14406                 }
14407                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14408                 {
14409                         if (findx > 0)
14410                                 appendPQExpBuffer(query, " OR UPDATE");
14411                         else
14412                                 appendPQExpBuffer(query, " UPDATE");
14413                         findx++;
14414                 }
14415                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14416                 {
14417                         if (findx > 0)
14418                                 appendPQExpBuffer(query, " OR TRUNCATE");
14419                         else
14420                                 appendPQExpBuffer(query, " TRUNCATE");
14421                         findx++;
14422                 }
14423                 appendPQExpBuffer(query, " ON %s\n",
14424                                                   fmtId(tbinfo->dobj.name));
14425
14426                 if (tginfo->tgisconstraint)
14427                 {
14428                         if (OidIsValid(tginfo->tgconstrrelid))
14429                         {
14430                                 /* If we are using regclass, name is already quoted */
14431                                 if (fout->remoteVersion >= 70300)
14432                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14433                                                                           tginfo->tgconstrrelname);
14434                                 else
14435                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14436                                                                           fmtId(tginfo->tgconstrrelname));
14437                         }
14438                         if (!tginfo->tgdeferrable)
14439                                 appendPQExpBuffer(query, "NOT ");
14440                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
14441                         if (tginfo->tginitdeferred)
14442                                 appendPQExpBuffer(query, "DEFERRED\n");
14443                         else
14444                                 appendPQExpBuffer(query, "IMMEDIATE\n");
14445                 }
14446
14447                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14448                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
14449                 else
14450                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
14451
14452                 /* In 7.3, result of regproc is already quoted */
14453                 if (fout->remoteVersion >= 70300)
14454                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14455                                                           tginfo->tgfname);
14456                 else
14457                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14458                                                           fmtId(tginfo->tgfname));
14459
14460                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14461                                                                                   &lentgargs);
14462                 p = tgargs;
14463                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14464                 {
14465                         /* find the embedded null that terminates this trigger argument */
14466                         size_t          tlen = strlen(p);
14467
14468                         if (p + tlen >= tgargs + lentgargs)
14469                         {
14470                                 /* hm, not found before end of bytea value... */
14471                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14472                                                   tginfo->tgargs,
14473                                                   tginfo->dobj.name,
14474                                                   tbinfo->dobj.name);
14475                                 exit_nicely(1);
14476                         }
14477
14478                         if (findx > 0)
14479                                 appendPQExpBuffer(query, ", ");
14480                         appendStringLiteralAH(query, p, fout);
14481                         p += tlen + 1;
14482                 }
14483                 free(tgargs);
14484                 appendPQExpBuffer(query, ");\n");
14485         }
14486
14487         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14488         {
14489                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
14490                                                   fmtId(tbinfo->dobj.name));
14491                 switch (tginfo->tgenabled)
14492                 {
14493                         case 'D':
14494                         case 'f':
14495                                 appendPQExpBuffer(query, "DISABLE");
14496                                 break;
14497                         case 'A':
14498                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14499                                 break;
14500                         case 'R':
14501                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14502                                 break;
14503                         default:
14504                                 appendPQExpBuffer(query, "ENABLE");
14505                                 break;
14506                 }
14507                 appendPQExpBuffer(query, " TRIGGER %s;\n",
14508                                                   fmtId(tginfo->dobj.name));
14509         }
14510
14511         appendPQExpBuffer(labelq, "TRIGGER %s ",
14512                                           fmtId(tginfo->dobj.name));
14513         appendPQExpBuffer(labelq, "ON %s",
14514                                           fmtId(tbinfo->dobj.name));
14515
14516         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14517                                  tginfo->dobj.name,
14518                                  tbinfo->dobj.namespace->dobj.name,
14519                                  NULL,
14520                                  tbinfo->rolname, false,
14521                                  "TRIGGER", SECTION_POST_DATA,
14522                                  query->data, delqry->data, NULL,
14523                                  NULL, 0,
14524                                  NULL, NULL);
14525
14526         dumpComment(fout, labelq->data,
14527                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14528                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14529
14530         destroyPQExpBuffer(query);
14531         destroyPQExpBuffer(delqry);
14532         destroyPQExpBuffer(labelq);
14533 }
14534
14535 static void
14536 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14537 {
14538         PQExpBuffer query;
14539         PQExpBuffer labelq;
14540
14541         query = createPQExpBuffer();
14542         labelq = createPQExpBuffer();
14543
14544         appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
14545         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14546         appendPQExpBuffer(query, " ON ");
14547         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14548         appendPQExpBufferStr(query, " ");
14549
14550         if (strcmp("", evtinfo->evttags) != 0)
14551         {
14552                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14553                 appendPQExpBufferStr(query, evtinfo->evttags);
14554                 appendPQExpBufferStr(query, ") ");
14555         }
14556
14557         appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
14558         appendPQExpBufferStr(query, evtinfo->evtfname);
14559         appendPQExpBuffer(query, "();\n");
14560
14561         if (evtinfo->evtenabled != 'O')
14562         {
14563                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14564                                                   fmtId(evtinfo->dobj.name));
14565                 switch (evtinfo->evtenabled)
14566                 {
14567                         case 'D':
14568                                 appendPQExpBuffer(query, "DISABLE");
14569                                 break;
14570                         case 'A':
14571                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14572                                 break;
14573                         case 'R':
14574                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14575                                 break;
14576                         default:
14577                                 appendPQExpBuffer(query, "ENABLE");
14578                                 break;
14579                 }
14580                 appendPQExpBuffer(query, ";\n");
14581         }
14582         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14583                                           fmtId(evtinfo->dobj.name));
14584
14585         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14586                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14587                                  "EVENT TRIGGER", SECTION_POST_DATA,
14588                                  query->data, "", NULL, NULL, 0, NULL, NULL);
14589
14590         dumpComment(fout, labelq->data,
14591                                 NULL, NULL,
14592                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14593
14594         destroyPQExpBuffer(query);
14595         destroyPQExpBuffer(labelq);
14596 }
14597
14598 /*
14599  * dumpRule
14600  *              Dump a rule
14601  */
14602 static void
14603 dumpRule(Archive *fout, RuleInfo *rinfo)
14604 {
14605         TableInfo  *tbinfo = rinfo->ruletable;
14606         PQExpBuffer query;
14607         PQExpBuffer cmd;
14608         PQExpBuffer delcmd;
14609         PQExpBuffer labelq;
14610         PGresult   *res;
14611
14612         /* Skip if not to be dumped */
14613         if (!rinfo->dobj.dump || dataOnly)
14614                 return;
14615
14616         /*
14617          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14618          * we do not want to dump it as a separate object.
14619          */
14620         if (!rinfo->separate)
14621                 return;
14622
14623         /*
14624          * Make sure we are in proper schema.
14625          */
14626         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14627
14628         query = createPQExpBuffer();
14629         cmd = createPQExpBuffer();
14630         delcmd = createPQExpBuffer();
14631         labelq = createPQExpBuffer();
14632
14633         if (fout->remoteVersion >= 70300)
14634         {
14635                 appendPQExpBuffer(query,
14636                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14637                                                   rinfo->dobj.catId.oid);
14638         }
14639         else
14640         {
14641                 /* Rule name was unique before 7.3 ... */
14642                 appendPQExpBuffer(query,
14643                                                   "SELECT pg_get_ruledef('%s') AS definition",
14644                                                   rinfo->dobj.name);
14645         }
14646
14647         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14648
14649         if (PQntuples(res) != 1)
14650         {
14651                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14652                                   rinfo->dobj.name, tbinfo->dobj.name);
14653                 exit_nicely(1);
14654         }
14655
14656         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14657
14658         /*
14659          * Add the command to alter the rules replication firing semantics if it
14660          * differs from the default.
14661          */
14662         if (rinfo->ev_enabled != 'O')
14663         {
14664                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14665                 switch (rinfo->ev_enabled)
14666                 {
14667                         case 'A':
14668                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14669                                                                   fmtId(rinfo->dobj.name));
14670                                 break;
14671                         case 'R':
14672                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14673                                                                   fmtId(rinfo->dobj.name));
14674                                 break;
14675                         case 'D':
14676                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14677                                                                   fmtId(rinfo->dobj.name));
14678                                 break;
14679                 }
14680         }
14681
14682         /*
14683          * Apply view's reloptions when its ON SELECT rule is separate.
14684          */
14685         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14686         {
14687                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14688                                                   fmtId(tbinfo->dobj.name),
14689                                                   rinfo->reloptions);
14690         }
14691
14692         /*
14693          * DROP must be fully qualified in case same name appears in pg_catalog
14694          */
14695         appendPQExpBuffer(delcmd, "DROP RULE %s ",
14696                                           fmtId(rinfo->dobj.name));
14697         appendPQExpBuffer(delcmd, "ON %s.",
14698                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14699         appendPQExpBuffer(delcmd, "%s;\n",
14700                                           fmtId(tbinfo->dobj.name));
14701
14702         appendPQExpBuffer(labelq, "RULE %s",
14703                                           fmtId(rinfo->dobj.name));
14704         appendPQExpBuffer(labelq, " ON %s",
14705                                           fmtId(tbinfo->dobj.name));
14706
14707         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14708                                  rinfo->dobj.name,
14709                                  tbinfo->dobj.namespace->dobj.name,
14710                                  NULL,
14711                                  tbinfo->rolname, false,
14712                                  "RULE", SECTION_POST_DATA,
14713                                  cmd->data, delcmd->data, NULL,
14714                                  NULL, 0,
14715                                  NULL, NULL);
14716
14717         /* Dump rule comments */
14718         dumpComment(fout, labelq->data,
14719                                 tbinfo->dobj.namespace->dobj.name,
14720                                 tbinfo->rolname,
14721                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14722
14723         PQclear(res);
14724
14725         destroyPQExpBuffer(query);
14726         destroyPQExpBuffer(cmd);
14727         destroyPQExpBuffer(delcmd);
14728         destroyPQExpBuffer(labelq);
14729 }
14730
14731 /*
14732  * getExtensionMembership --- obtain extension membership data
14733  */
14734 void
14735 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14736                                            int numExtensions)
14737 {
14738         PQExpBuffer query;
14739         PGresult   *res;
14740         int                     ntups,
14741                                 i;
14742         int                     i_classid,
14743                                 i_objid,
14744                                 i_refclassid,
14745                                 i_refobjid;
14746         DumpableObject *dobj,
14747                            *refdobj;
14748
14749         /* Nothing to do if no extensions */
14750         if (numExtensions == 0)
14751                 return;
14752
14753         /* Make sure we are in proper schema */
14754         selectSourceSchema(fout, "pg_catalog");
14755
14756         query = createPQExpBuffer();
14757
14758         /* refclassid constraint is redundant but may speed the search */
14759         appendPQExpBuffer(query, "SELECT "
14760                                           "classid, objid, refclassid, refobjid "
14761                                           "FROM pg_depend "
14762                                           "WHERE refclassid = 'pg_extension'::regclass "
14763                                           "AND deptype = 'e' "
14764                                           "ORDER BY 3,4");
14765
14766         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14767
14768         ntups = PQntuples(res);
14769
14770         i_classid = PQfnumber(res, "classid");
14771         i_objid = PQfnumber(res, "objid");
14772         i_refclassid = PQfnumber(res, "refclassid");
14773         i_refobjid = PQfnumber(res, "refobjid");
14774
14775         /*
14776          * Since we ordered the SELECT by referenced ID, we can expect that
14777          * multiple entries for the same extension will appear together; this
14778          * saves on searches.
14779          */
14780         refdobj = NULL;
14781
14782         for (i = 0; i < ntups; i++)
14783         {
14784                 CatalogId       objId;
14785                 CatalogId       refobjId;
14786
14787                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14788                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14789                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14790                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14791
14792                 if (refdobj == NULL ||
14793                         refdobj->catId.tableoid != refobjId.tableoid ||
14794                         refdobj->catId.oid != refobjId.oid)
14795                         refdobj = findObjectByCatalogId(refobjId);
14796
14797                 /*
14798                  * Failure to find objects mentioned in pg_depend is not unexpected,
14799                  * since for example we don't collect info about TOAST tables.
14800                  */
14801                 if (refdobj == NULL)
14802                 {
14803 #ifdef NOT_USED
14804                         fprintf(stderr, "no referenced object %u %u\n",
14805                                         refobjId.tableoid, refobjId.oid);
14806 #endif
14807                         continue;
14808                 }
14809
14810                 dobj = findObjectByCatalogId(objId);
14811
14812                 if (dobj == NULL)
14813                 {
14814 #ifdef NOT_USED
14815                         fprintf(stderr, "no referencing object %u %u\n",
14816                                         objId.tableoid, objId.oid);
14817 #endif
14818                         continue;
14819                 }
14820
14821                 /* Record dependency so that getDependencies needn't repeat this */
14822                 addObjectDependency(dobj, refdobj->dumpId);
14823
14824                 dobj->ext_member = true;
14825
14826                 /*
14827                  * Normally, mark the member object as not to be dumped.  But in
14828                  * binary upgrades, we still dump the members individually, since the
14829                  * idea is to exactly reproduce the database contents rather than
14830                  * replace the extension contents with something different.
14831                  */
14832                 if (!binary_upgrade)
14833                         dobj->dump = false;
14834                 else
14835                         dobj->dump = refdobj->dump;
14836         }
14837
14838         PQclear(res);
14839
14840         /*
14841          * Now identify extension configuration tables and create TableDataInfo
14842          * objects for them, ensuring their data will be dumped even though the
14843          * tables themselves won't be.
14844          *
14845          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14846          * user data in a configuration table is treated like schema data. This
14847          * seems appropriate since system data in a config table would get
14848          * reloaded by CREATE EXTENSION.
14849          */
14850         for (i = 0; i < numExtensions; i++)
14851         {
14852                 ExtensionInfo *curext = &(extinfo[i]);
14853                 char       *extconfig = curext->extconfig;
14854                 char       *extcondition = curext->extcondition;
14855                 char      **extconfigarray = NULL;
14856                 char      **extconditionarray = NULL;
14857                 int                     nconfigitems;
14858                 int                     nconditionitems;
14859
14860                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14861                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14862                         nconfigitems == nconditionitems)
14863                 {
14864                         int                     j;
14865
14866                         for (j = 0; j < nconfigitems; j++)
14867                         {
14868                                 TableInfo  *configtbl;
14869                                 Oid                     configtbloid = atooid(extconfigarray[j]);
14870                                 bool            dumpobj = curext->dobj.dump;
14871
14872                                 configtbl = findTableByOid(configtbloid);
14873                                 if (configtbl == NULL)
14874                                         continue;
14875
14876                                 /*
14877                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
14878                                  * unless the table or its schema is explicitly included
14879                                  */
14880                                 if (!curext->dobj.dump)
14881                                 {
14882                                         /* check table explicitly requested */
14883                                         if (table_include_oids.head != NULL &&
14884                                                 simple_oid_list_member(&table_include_oids,
14885                                                                                            configtbloid))
14886                                                 dumpobj = true;
14887
14888                                         /* check table's schema explicitly requested */
14889                                         if (configtbl->dobj.namespace->dobj.dump)
14890                                                 dumpobj = true;
14891                                 }
14892
14893                                 /* check table excluded by an exclusion switch */
14894                                 if (table_exclude_oids.head != NULL &&
14895                                         simple_oid_list_member(&table_exclude_oids,
14896                                                                                    configtbloid))
14897                                         dumpobj = false;
14898
14899                                 /* check schema excluded by an exclusion switch */
14900                                 if (simple_oid_list_member(&schema_exclude_oids,
14901                                                                   configtbl->dobj.namespace->dobj.catId.oid))
14902                                         dumpobj = false;
14903
14904                                 if (dumpobj)
14905                                 {
14906                                         /*
14907                                          * Note: config tables are dumped without OIDs regardless
14908                                          * of the --oids setting.  This is because row filtering
14909                                          * conditions aren't compatible with dumping OIDs.
14910                                          */
14911                                         makeTableDataInfo(configtbl, false);
14912                                         if (configtbl->dataObj != NULL)
14913                                         {
14914                                                 if (strlen(extconditionarray[j]) > 0)
14915                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14916                                         }
14917                                 }
14918                         }
14919                 }
14920                 if (extconfigarray)
14921                         free(extconfigarray);
14922                 if (extconditionarray)
14923                         free(extconditionarray);
14924         }
14925
14926         destroyPQExpBuffer(query);
14927 }
14928
14929 /*
14930  * getDependencies --- obtain available dependency data
14931  */
14932 static void
14933 getDependencies(Archive *fout)
14934 {
14935         PQExpBuffer query;
14936         PGresult   *res;
14937         int                     ntups,
14938                                 i;
14939         int                     i_classid,
14940                                 i_objid,
14941                                 i_refclassid,
14942                                 i_refobjid,
14943                                 i_deptype;
14944         DumpableObject *dobj,
14945                            *refdobj;
14946
14947         /* No dependency info available before 7.3 */
14948         if (fout->remoteVersion < 70300)
14949                 return;
14950
14951         if (g_verbose)
14952                 write_msg(NULL, "reading dependency data\n");
14953
14954         /* Make sure we are in proper schema */
14955         selectSourceSchema(fout, "pg_catalog");
14956
14957         query = createPQExpBuffer();
14958
14959         /*
14960          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14961          * already processed by getExtensionMembership.
14962          */
14963         appendPQExpBuffer(query, "SELECT "
14964                                           "classid, objid, refclassid, refobjid, deptype "
14965                                           "FROM pg_depend "
14966                                           "WHERE deptype != 'p' AND deptype != 'e' "
14967                                           "ORDER BY 1,2");
14968
14969         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14970
14971         ntups = PQntuples(res);
14972
14973         i_classid = PQfnumber(res, "classid");
14974         i_objid = PQfnumber(res, "objid");
14975         i_refclassid = PQfnumber(res, "refclassid");
14976         i_refobjid = PQfnumber(res, "refobjid");
14977         i_deptype = PQfnumber(res, "deptype");
14978
14979         /*
14980          * Since we ordered the SELECT by referencing ID, we can expect that
14981          * multiple entries for the same object will appear together; this saves
14982          * on searches.
14983          */
14984         dobj = NULL;
14985
14986         for (i = 0; i < ntups; i++)
14987         {
14988                 CatalogId       objId;
14989                 CatalogId       refobjId;
14990                 char            deptype;
14991
14992                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14993                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14994                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14995                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14996                 deptype = *(PQgetvalue(res, i, i_deptype));
14997
14998                 if (dobj == NULL ||
14999                         dobj->catId.tableoid != objId.tableoid ||
15000                         dobj->catId.oid != objId.oid)
15001                         dobj = findObjectByCatalogId(objId);
15002
15003                 /*
15004                  * Failure to find objects mentioned in pg_depend is not unexpected,
15005                  * since for example we don't collect info about TOAST tables.
15006                  */
15007                 if (dobj == NULL)
15008                 {
15009 #ifdef NOT_USED
15010                         fprintf(stderr, "no referencing object %u %u\n",
15011                                         objId.tableoid, objId.oid);
15012 #endif
15013                         continue;
15014                 }
15015
15016                 refdobj = findObjectByCatalogId(refobjId);
15017
15018                 if (refdobj == NULL)
15019                 {
15020 #ifdef NOT_USED
15021                         fprintf(stderr, "no referenced object %u %u\n",
15022                                         refobjId.tableoid, refobjId.oid);
15023 #endif
15024                         continue;
15025                 }
15026
15027                 /*
15028                  * Ordinarily, table rowtypes have implicit dependencies on their
15029                  * tables.      However, for a composite type the implicit dependency goes
15030                  * the other way in pg_depend; which is the right thing for DROP but
15031                  * it doesn't produce the dependency ordering we need. So in that one
15032                  * case, we reverse the direction of the dependency.
15033                  */
15034                 if (deptype == 'i' &&
15035                         dobj->objType == DO_TABLE &&
15036                         refdobj->objType == DO_TYPE)
15037                         addObjectDependency(refdobj, dobj->dumpId);
15038                 else
15039                         /* normal case */
15040                         addObjectDependency(dobj, refdobj->dumpId);
15041         }
15042
15043         PQclear(res);
15044
15045         destroyPQExpBuffer(query);
15046 }
15047
15048
15049 /*
15050  * createBoundaryObjects - create dummy DumpableObjects to represent
15051  * dump section boundaries.
15052  */
15053 static DumpableObject *
15054 createBoundaryObjects(void)
15055 {
15056         DumpableObject *dobjs;
15057
15058         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
15059
15060         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
15061         dobjs[0].catId = nilCatalogId;
15062         AssignDumpId(dobjs + 0);
15063         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
15064
15065         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
15066         dobjs[1].catId = nilCatalogId;
15067         AssignDumpId(dobjs + 1);
15068         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
15069
15070         return dobjs;
15071 }
15072
15073 /*
15074  * addBoundaryDependencies - add dependencies as needed to enforce the dump
15075  * section boundaries.
15076  */
15077 static void
15078 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
15079                                                 DumpableObject *boundaryObjs)
15080 {
15081         DumpableObject *preDataBound = boundaryObjs + 0;
15082         DumpableObject *postDataBound = boundaryObjs + 1;
15083         int                     i;
15084
15085         for (i = 0; i < numObjs; i++)
15086         {
15087                 DumpableObject *dobj = dobjs[i];
15088
15089                 /*
15090                  * The classification of object types here must match the SECTION_xxx
15091                  * values assigned during subsequent ArchiveEntry calls!
15092                  */
15093                 switch (dobj->objType)
15094                 {
15095                         case DO_NAMESPACE:
15096                         case DO_EXTENSION:
15097                         case DO_TYPE:
15098                         case DO_SHELL_TYPE:
15099                         case DO_FUNC:
15100                         case DO_AGG:
15101                         case DO_OPERATOR:
15102                         case DO_OPCLASS:
15103                         case DO_OPFAMILY:
15104                         case DO_COLLATION:
15105                         case DO_CONVERSION:
15106                         case DO_TABLE:
15107                         case DO_ATTRDEF:
15108                         case DO_PROCLANG:
15109                         case DO_CAST:
15110                         case DO_DUMMY_TYPE:
15111                         case DO_TSPARSER:
15112                         case DO_TSDICT:
15113                         case DO_TSTEMPLATE:
15114                         case DO_TSCONFIG:
15115                         case DO_FDW:
15116                         case DO_FOREIGN_SERVER:
15117                         case DO_BLOB:
15118                                 /* Pre-data objects: must come before the pre-data boundary */
15119                                 addObjectDependency(preDataBound, dobj->dumpId);
15120                                 break;
15121                         case DO_TABLE_DATA:
15122                         case DO_BLOB_DATA:
15123                                 /* Data objects: must come between the boundaries */
15124                                 addObjectDependency(dobj, preDataBound->dumpId);
15125                                 addObjectDependency(postDataBound, dobj->dumpId);
15126                                 break;
15127                         case DO_INDEX:
15128                         case DO_REFRESH_MATVIEW:
15129                         case DO_TRIGGER:
15130                         case DO_EVENT_TRIGGER:
15131                         case DO_DEFAULT_ACL:
15132                                 /* Post-data objects: must come after the post-data boundary */
15133                                 addObjectDependency(dobj, postDataBound->dumpId);
15134                                 break;
15135                         case DO_RULE:
15136                                 /* Rules are post-data, but only if dumped separately */
15137                                 if (((RuleInfo *) dobj)->separate)
15138                                         addObjectDependency(dobj, postDataBound->dumpId);
15139                                 break;
15140                         case DO_CONSTRAINT:
15141                         case DO_FK_CONSTRAINT:
15142                                 /* Constraints are post-data, but only if dumped separately */
15143                                 if (((ConstraintInfo *) dobj)->separate)
15144                                         addObjectDependency(dobj, postDataBound->dumpId);
15145                                 break;
15146                         case DO_PRE_DATA_BOUNDARY:
15147                                 /* nothing to do */
15148                                 break;
15149                         case DO_POST_DATA_BOUNDARY:
15150                                 /* must come after the pre-data boundary */
15151                                 addObjectDependency(dobj, preDataBound->dumpId);
15152                                 break;
15153                 }
15154         }
15155 }
15156
15157
15158 /*
15159  * BuildArchiveDependencies - create dependency data for archive TOC entries
15160  *
15161  * The raw dependency data obtained by getDependencies() is not terribly
15162  * useful in an archive dump, because in many cases there are dependency
15163  * chains linking through objects that don't appear explicitly in the dump.
15164  * For example, a view will depend on its _RETURN rule while the _RETURN rule
15165  * will depend on other objects --- but the rule will not appear as a separate
15166  * object in the dump.  We need to adjust the view's dependencies to include
15167  * whatever the rule depends on that is included in the dump.
15168  *
15169  * Just to make things more complicated, there are also "special" dependencies
15170  * such as the dependency of a TABLE DATA item on its TABLE, which we must
15171  * not rearrange because pg_restore knows that TABLE DATA only depends on
15172  * its table.  In these cases we must leave the dependencies strictly as-is
15173  * even if they refer to not-to-be-dumped objects.
15174  *
15175  * To handle this, the convention is that "special" dependencies are created
15176  * during ArchiveEntry calls, and an archive TOC item that has any such
15177  * entries will not be touched here.  Otherwise, we recursively search the
15178  * DumpableObject data structures to build the correct dependencies for each
15179  * archive TOC item.
15180  */
15181 static void
15182 BuildArchiveDependencies(Archive *fout)
15183 {
15184         ArchiveHandle *AH = (ArchiveHandle *) fout;
15185         TocEntry   *te;
15186
15187         /* Scan all TOC entries in the archive */
15188         for (te = AH->toc->next; te != AH->toc; te = te->next)
15189         {
15190                 DumpableObject *dobj;
15191                 DumpId     *dependencies;
15192                 int                     nDeps;
15193                 int                     allocDeps;
15194
15195                 /* No need to process entries that will not be dumped */
15196                 if (te->reqs == 0)
15197                         continue;
15198                 /* Ignore entries that already have "special" dependencies */
15199                 if (te->nDeps > 0)
15200                         continue;
15201                 /* Otherwise, look up the item's original DumpableObject, if any */
15202                 dobj = findObjectByDumpId(te->dumpId);
15203                 if (dobj == NULL)
15204                         continue;
15205                 /* No work if it has no dependencies */
15206                 if (dobj->nDeps <= 0)
15207                         continue;
15208                 /* Set up work array */
15209                 allocDeps = 64;
15210                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
15211                 nDeps = 0;
15212                 /* Recursively find all dumpable dependencies */
15213                 findDumpableDependencies(AH, dobj,
15214                                                                  &dependencies, &nDeps, &allocDeps);
15215                 /* And save 'em ... */
15216                 if (nDeps > 0)
15217                 {
15218                         dependencies = (DumpId *) pg_realloc(dependencies,
15219                                                                                                  nDeps * sizeof(DumpId));
15220                         te->dependencies = dependencies;
15221                         te->nDeps = nDeps;
15222                 }
15223                 else
15224                         free(dependencies);
15225         }
15226 }
15227
15228 /* Recursive search subroutine for BuildArchiveDependencies */
15229 static void
15230 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
15231                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
15232 {
15233         int                     i;
15234
15235         /*
15236          * Ignore section boundary objects: if we search through them, we'll
15237          * report lots of bogus dependencies.
15238          */
15239         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15240                 dobj->objType == DO_POST_DATA_BOUNDARY)
15241                 return;
15242
15243         for (i = 0; i < dobj->nDeps; i++)
15244         {
15245                 DumpId          depid = dobj->dependencies[i];
15246
15247                 if (TocIDRequired(AH, depid) != 0)
15248                 {
15249                         /* Object will be dumped, so just reference it as a dependency */
15250                         if (*nDeps >= *allocDeps)
15251                         {
15252                                 *allocDeps *= 2;
15253                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15254                                                                                                 *allocDeps * sizeof(DumpId));
15255                         }
15256                         (*dependencies)[*nDeps] = depid;
15257                         (*nDeps)++;
15258                 }
15259                 else
15260                 {
15261                         /*
15262                          * Object will not be dumped, so recursively consider its deps. We
15263                          * rely on the assumption that sortDumpableObjects already broke
15264                          * any dependency loops, else we might recurse infinitely.
15265                          */
15266                         DumpableObject *otherdobj = findObjectByDumpId(depid);
15267
15268                         if (otherdobj)
15269                                 findDumpableDependencies(AH, otherdobj,
15270                                                                                  dependencies, nDeps, allocDeps);
15271                 }
15272         }
15273 }
15274
15275
15276 /*
15277  * selectSourceSchema - make the specified schema the active search path
15278  * in the source database.
15279  *
15280  * NB: pg_catalog is explicitly searched after the specified schema;
15281  * so user names are only qualified if they are cross-schema references,
15282  * and system names are only qualified if they conflict with a user name
15283  * in the current schema.
15284  *
15285  * Whenever the selected schema is not pg_catalog, be careful to qualify
15286  * references to system catalogs and types in our emitted commands!
15287  *
15288  * This function is called only from selectSourceSchemaOnAH and
15289  * selectSourceSchema.
15290  */
15291 static void
15292 selectSourceSchema(Archive *fout, const char *schemaName)
15293 {
15294         PQExpBuffer query;
15295
15296         /* This is checked by the callers already */
15297         Assert(schemaName != NULL && *schemaName != '\0');
15298
15299         /* Not relevant if fetching from pre-7.3 DB */
15300         if (fout->remoteVersion < 70300)
15301                 return;
15302
15303         query = createPQExpBuffer();
15304         appendPQExpBuffer(query, "SET search_path = %s",
15305                                           fmtId(schemaName));
15306         if (strcmp(schemaName, "pg_catalog") != 0)
15307                 appendPQExpBuffer(query, ", pg_catalog");
15308
15309         ExecuteSqlStatement(fout, query->data);
15310
15311         destroyPQExpBuffer(query);
15312 }
15313
15314 /*
15315  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15316  * given type name.
15317  *
15318  * NB: in 7.3 and up the result may depend on the currently-selected
15319  * schema; this is why we don't try to cache the names.
15320  */
15321 static char *
15322 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15323 {
15324         char       *result;
15325         PQExpBuffer query;
15326         PGresult   *res;
15327
15328         if (oid == 0)
15329         {
15330                 if ((opts & zeroAsOpaque) != 0)
15331                         return pg_strdup(g_opaque_type);
15332                 else if ((opts & zeroAsAny) != 0)
15333                         return pg_strdup("'any'");
15334                 else if ((opts & zeroAsStar) != 0)
15335                         return pg_strdup("*");
15336                 else if ((opts & zeroAsNone) != 0)
15337                         return pg_strdup("NONE");
15338         }
15339
15340         query = createPQExpBuffer();
15341         if (fout->remoteVersion >= 70300)
15342         {
15343                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15344                                                   oid);
15345         }
15346         else if (fout->remoteVersion >= 70100)
15347         {
15348                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15349                                                   oid);
15350         }
15351         else
15352         {
15353                 appendPQExpBuffer(query, "SELECT typname "
15354                                                   "FROM pg_type "
15355                                                   "WHERE oid = '%u'::oid",
15356                                                   oid);
15357         }
15358
15359         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15360
15361         if (fout->remoteVersion >= 70100)
15362         {
15363                 /* already quoted */
15364                 result = pg_strdup(PQgetvalue(res, 0, 0));
15365         }
15366         else
15367         {
15368                 /* may need to quote it */
15369                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15370         }
15371
15372         PQclear(res);
15373         destroyPQExpBuffer(query);
15374
15375         return result;
15376 }
15377
15378 /*
15379  * myFormatType --- local implementation of format_type for use with 7.0.
15380  */
15381 static char *
15382 myFormatType(const char *typname, int32 typmod)
15383 {
15384         char       *result;
15385         bool            isarray = false;
15386         PQExpBuffer buf = createPQExpBuffer();
15387
15388         /* Handle array types */
15389         if (typname[0] == '_')
15390         {
15391                 isarray = true;
15392                 typname++;
15393         }
15394
15395         /* Show lengths on bpchar and varchar */
15396         if (strcmp(typname, "bpchar") == 0)
15397         {
15398                 int                     len = (typmod - VARHDRSZ);
15399
15400                 appendPQExpBuffer(buf, "character");
15401                 if (len > 1)
15402                         appendPQExpBuffer(buf, "(%d)",
15403                                                           typmod - VARHDRSZ);
15404         }
15405         else if (strcmp(typname, "varchar") == 0)
15406         {
15407                 appendPQExpBuffer(buf, "character varying");
15408                 if (typmod != -1)
15409                         appendPQExpBuffer(buf, "(%d)",
15410                                                           typmod - VARHDRSZ);
15411         }
15412         else if (strcmp(typname, "numeric") == 0)
15413         {
15414                 appendPQExpBuffer(buf, "numeric");
15415                 if (typmod != -1)
15416                 {
15417                         int32           tmp_typmod;
15418                         int                     precision;
15419                         int                     scale;
15420
15421                         tmp_typmod = typmod - VARHDRSZ;
15422                         precision = (tmp_typmod >> 16) & 0xffff;
15423                         scale = tmp_typmod & 0xffff;
15424                         appendPQExpBuffer(buf, "(%d,%d)",
15425                                                           precision, scale);
15426                 }
15427         }
15428
15429         /*
15430          * char is an internal single-byte data type; Let's make sure we force it
15431          * through with quotes. - thomas 1998-12-13
15432          */
15433         else if (strcmp(typname, "char") == 0)
15434                 appendPQExpBuffer(buf, "\"char\"");
15435         else
15436                 appendPQExpBuffer(buf, "%s", fmtId(typname));
15437
15438         /* Append array qualifier for array types */
15439         if (isarray)
15440                 appendPQExpBuffer(buf, "[]");
15441
15442         result = pg_strdup(buf->data);
15443         destroyPQExpBuffer(buf);
15444
15445         return result;
15446 }
15447
15448 /*
15449  * Return a column list clause for the given relation.
15450  *
15451  * Special case: if there are no undropped columns in the relation, return
15452  * "", not an invalid "()" column list.
15453  */
15454 static const char *
15455 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15456 {
15457         int                     numatts = ti->numatts;
15458         char      **attnames = ti->attnames;
15459         bool       *attisdropped = ti->attisdropped;
15460         bool            needComma;
15461         int                     i;
15462
15463         appendPQExpBuffer(buffer, "(");
15464         needComma = false;
15465         for (i = 0; i < numatts; i++)
15466         {
15467                 if (attisdropped[i])
15468                         continue;
15469                 if (needComma)
15470                         appendPQExpBuffer(buffer, ", ");
15471                 appendPQExpBuffer(buffer, "%s", fmtId(attnames[i]));
15472                 needComma = true;
15473         }
15474
15475         if (!needComma)
15476                 return "";                              /* no undropped columns */
15477
15478         appendPQExpBuffer(buffer, ")");
15479         return buffer->data;
15480 }
15481
15482 /*
15483  * Execute an SQL query and verify that we got exactly one row back.
15484  */
15485 static PGresult *
15486 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15487 {
15488         PGresult   *res;
15489         int                     ntups;
15490
15491         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15492
15493         /* Expecting a single result only */
15494         ntups = PQntuples(res);
15495         if (ntups != 1)
15496                 exit_horribly(NULL,
15497                                           ngettext("query returned %d row instead of one: %s\n",
15498                                                            "query returned %d rows instead of one: %s\n",
15499                                                            ntups),
15500                                           ntups, query);
15501
15502         return res;
15503 }