]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Ensure that user created rows in extension tables get dumped if the table is explicit...
[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 run on
18  *      SnapshotNow time, ie they look at the currently committed state.  So
19  *      it is possible to get 'cache lookup failed' error if someone
20  *      performs DDL changes while a dump is happening. The window for this
21  *      sort of thing is from the acquisition of the transaction snapshot to
22  *      getSchemaData() (when pg_dump acquires AccessShareLock on every
23  *      table it intends to dump). It isn't very large, 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 static char *format_function_arguments_old(Archive *fout,
234                                                           FuncInfo *finfo, int nallargs,
235                                                           char **allargtypes,
236                                                           char **argmodes,
237                                                           char **argnames);
238 static char *format_function_signature(Archive *fout,
239                                                   FuncInfo *finfo, bool honor_quotes);
240 static const char *convertRegProcReference(Archive *fout,
241                                                 const char *proc);
242 static const char *convertOperatorReference(Archive *fout, const char *opr);
243 static const char *convertTSFunction(Archive *fout, Oid funcOid);
244 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
245 static Oid      findLastBuiltinOid_V70(Archive *fout);
246 static void selectSourceSchema(Archive *fout, const char *schemaName);
247 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
248 static char *myFormatType(const char *typname, int32 typmod);
249 static void getBlobs(Archive *fout);
250 static void dumpBlob(Archive *fout, BlobInfo *binfo);
251 static int      dumpBlobs(Archive *fout, void *arg);
252 static void dumpDatabase(Archive *AH);
253 static void dumpEncoding(Archive *AH);
254 static void dumpStdStrings(Archive *AH);
255 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
256                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
257 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
258                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
259 static void binary_upgrade_set_pg_class_oids(Archive *fout,
260                                                                  PQExpBuffer upgrade_buffer,
261                                                                  Oid pg_class_oid, bool is_index);
262 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
263                                                                 DumpableObject *dobj,
264                                                                 const char *objlabel);
265 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
266 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
267 static char *get_synchronized_snapshot(Archive *fout);
268 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
269 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
270
271
272 int
273 main(int argc, char **argv)
274 {
275         int                     c;
276         const char *filename = NULL;
277         const char *format = "p";
278         const char *dbname = NULL;
279         const char *pghost = NULL;
280         const char *pgport = NULL;
281         const char *username = NULL;
282         const char *dumpencoding = NULL;
283         bool            oids = false;
284         TableInfo  *tblinfo;
285         int                     numTables;
286         DumpableObject **dobjs;
287         int                     numObjs;
288         DumpableObject *boundaryObjs;
289         int                     i;
290         int                     numWorkers = 1;
291         enum trivalue prompt_password = TRI_DEFAULT;
292         int                     compressLevel = -1;
293         int                     plainText = 0;
294         int                     outputClean = 0;
295         int                     outputCreateDB = 0;
296         bool            outputBlobs = false;
297         int                     outputNoOwner = 0;
298         char       *outputSuperuser = NULL;
299         char       *use_role = NULL;
300         int                     optindex;
301         RestoreOptions *ropt;
302         ArchiveFormat archiveFormat = archUnknown;
303         ArchiveMode archiveMode;
304         Archive    *fout;                       /* the script file */
305
306         static int      disable_triggers = 0;
307         static int      outputNoTablespaces = 0;
308         static int      use_setsessauth = 0;
309
310         static struct option long_options[] = {
311                 {"data-only", no_argument, NULL, 'a'},
312                 {"blobs", no_argument, NULL, 'b'},
313                 {"clean", no_argument, NULL, 'c'},
314                 {"create", no_argument, NULL, 'C'},
315                 {"dbname", required_argument, NULL, 'd'},
316                 {"file", required_argument, NULL, 'f'},
317                 {"format", required_argument, NULL, 'F'},
318                 {"host", required_argument, NULL, 'h'},
319                 {"ignore-version", no_argument, NULL, 'i'},
320                 {"jobs", 1, NULL, 'j'},
321                 {"no-reconnect", no_argument, NULL, 'R'},
322                 {"oids", no_argument, NULL, 'o'},
323                 {"no-owner", no_argument, NULL, 'O'},
324                 {"port", required_argument, NULL, 'p'},
325                 {"schema", required_argument, NULL, 'n'},
326                 {"exclude-schema", required_argument, NULL, 'N'},
327                 {"schema-only", no_argument, NULL, 's'},
328                 {"superuser", required_argument, NULL, 'S'},
329                 {"table", required_argument, NULL, 't'},
330                 {"exclude-table", required_argument, NULL, 'T'},
331                 {"no-password", no_argument, NULL, 'w'},
332                 {"password", no_argument, NULL, 'W'},
333                 {"username", required_argument, NULL, 'U'},
334                 {"verbose", no_argument, NULL, 'v'},
335                 {"no-privileges", no_argument, NULL, 'x'},
336                 {"no-acl", no_argument, NULL, 'x'},
337                 {"compress", required_argument, NULL, 'Z'},
338                 {"encoding", required_argument, NULL, 'E'},
339                 {"help", no_argument, NULL, '?'},
340                 {"version", no_argument, NULL, 'V'},
341
342                 /*
343                  * the following options don't have an equivalent short option letter
344                  */
345                 {"attribute-inserts", no_argument, &column_inserts, 1},
346                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
347                 {"column-inserts", no_argument, &column_inserts, 1},
348                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
349                 {"disable-triggers", no_argument, &disable_triggers, 1},
350                 {"exclude-table-data", required_argument, NULL, 4},
351                 {"inserts", no_argument, &dump_inserts, 1},
352                 {"lock-wait-timeout", required_argument, NULL, 2},
353                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
354                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
355                 {"role", required_argument, NULL, 3},
356                 {"section", required_argument, NULL, 5},
357                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
358                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
359                 {"no-security-labels", no_argument, &no_security_labels, 1},
360                 {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
361                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
362
363                 {NULL, 0, NULL, 0}
364         };
365
366         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
367
368         /*
369          * Initialize what we need for parallel execution, especially for thread
370          * support on Windows.
371          */
372         init_parallel_dump_utils();
373
374         g_verbose = false;
375
376         strcpy(g_comment_start, "-- ");
377         g_comment_end[0] = '\0';
378         strcpy(g_opaque_type, "opaque");
379
380         dataOnly = schemaOnly = false;
381         dumpSections = DUMP_UNSECTIONED;
382         lockWaitTimeout = NULL;
383
384         progname = get_progname(argv[0]);
385
386         /* Set default options based on progname */
387         if (strcmp(progname, "pg_backup") == 0)
388                 format = "c";
389
390         if (argc > 1)
391         {
392                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
393                 {
394                         help(progname);
395                         exit_nicely(0);
396                 }
397                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
398                 {
399                         puts("pg_dump (PostgreSQL) " PG_VERSION);
400                         exit_nicely(0);
401                 }
402         }
403
404         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:K:n:N:oOp:RsS:t:T:U:vwWxZ:",
405                                                         long_options, &optindex)) != -1)
406         {
407                 switch (c)
408                 {
409                         case 'a':                       /* Dump data only */
410                                 dataOnly = true;
411                                 break;
412
413                         case 'b':                       /* Dump blobs */
414                                 outputBlobs = true;
415                                 break;
416
417                         case 'c':                       /* clean (i.e., drop) schema prior to create */
418                                 outputClean = 1;
419                                 break;
420
421                         case 'C':                       /* Create DB */
422                                 outputCreateDB = 1;
423                                 break;
424
425                         case 'd':                       /* database name */
426                                 dbname = pg_strdup(optarg);
427                                 break;
428
429                         case 'E':                       /* Dump encoding */
430                                 dumpencoding = pg_strdup(optarg);
431                                 break;
432
433                         case 'f':
434                                 filename = pg_strdup(optarg);
435                                 break;
436
437                         case 'F':
438                                 format = pg_strdup(optarg);
439                                 break;
440
441                         case 'h':                       /* server host */
442                                 pghost = pg_strdup(optarg);
443                                 break;
444
445                         case 'i':
446                                 /* ignored, deprecated option */
447                                 break;
448
449                         case 'j':                       /* number of dump jobs */
450                                 numWorkers = atoi(optarg);
451                                 break;
452
453                         case 'n':                       /* include schema(s) */
454                                 simple_string_list_append(&schema_include_patterns, optarg);
455                                 include_everything = false;
456                                 break;
457
458                         case 'N':                       /* exclude schema(s) */
459                                 simple_string_list_append(&schema_exclude_patterns, optarg);
460                                 break;
461
462                         case 'o':                       /* Dump oids */
463                                 oids = true;
464                                 break;
465
466                         case 'O':                       /* Don't reconnect to match owner */
467                                 outputNoOwner = 1;
468                                 break;
469
470                         case 'p':                       /* server port */
471                                 pgport = pg_strdup(optarg);
472                                 break;
473
474                         case 'R':
475                                 /* no-op, still accepted for backwards compatibility */
476                                 break;
477
478                         case 's':                       /* dump schema only */
479                                 schemaOnly = true;
480                                 break;
481
482                         case 'S':                       /* Username for superuser in plain text output */
483                                 outputSuperuser = pg_strdup(optarg);
484                                 break;
485
486                         case 't':                       /* include table(s) */
487                                 simple_string_list_append(&table_include_patterns, optarg);
488                                 include_everything = false;
489                                 break;
490
491                         case 'T':                       /* exclude table(s) */
492                                 simple_string_list_append(&table_exclude_patterns, optarg);
493                                 break;
494
495                         case 'U':
496                                 username = pg_strdup(optarg);
497                                 break;
498
499                         case 'v':                       /* verbose */
500                                 g_verbose = true;
501                                 break;
502
503                         case 'w':
504                                 prompt_password = TRI_NO;
505                                 break;
506
507                         case 'W':
508                                 prompt_password = TRI_YES;
509                                 break;
510
511                         case 'x':                       /* skip ACL dump */
512                                 aclsSkip = true;
513                                 break;
514
515                         case 'Z':                       /* Compression Level */
516                                 compressLevel = atoi(optarg);
517                                 break;
518
519                         case 0:
520                                 /* This covers the long options. */
521                                 break;
522
523                         case 2:                         /* lock-wait-timeout */
524                                 lockWaitTimeout = pg_strdup(optarg);
525                                 break;
526
527                         case 3:                         /* SET ROLE */
528                                 use_role = pg_strdup(optarg);
529                                 break;
530
531                         case 4:                         /* exclude table(s) data */
532                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
533                                 break;
534
535                         case 5:                         /* section */
536                                 set_dump_section(optarg, &dumpSections);
537                                 break;
538
539                         default:
540                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
541                                 exit_nicely(1);
542                 }
543         }
544
545         /*
546          * Non-option argument specifies database name as long as it wasn't
547          * already specified with -d / --dbname
548          */
549         if (optind < argc && dbname == NULL)
550                 dbname = argv[optind++];
551
552         /* Complain if any arguments remain */
553         if (optind < argc)
554         {
555                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
556                                 progname, argv[optind]);
557                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
558                                 progname);
559                 exit_nicely(1);
560         }
561
562         /* --column-inserts implies --inserts */
563         if (column_inserts)
564                 dump_inserts = 1;
565
566         if (dataOnly && schemaOnly)
567                 exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
568
569         if (dataOnly && outputClean)
570                 exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
571
572         if (dump_inserts && oids)
573         {
574                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
575                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
576                 exit_nicely(1);
577         }
578
579         /* Identify archive format to emit */
580         archiveFormat = parseArchiveFormat(format, &archiveMode);
581
582         /* archiveFormat specific setup */
583         if (archiveFormat == archNull)
584                 plainText = 1;
585
586         /* Custom and directory formats are compressed by default, others not */
587         if (compressLevel == -1)
588         {
589                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
590                         compressLevel = Z_DEFAULT_COMPRESSION;
591                 else
592                         compressLevel = 0;
593         }
594
595         /*
596          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
597          * parallel jobs because that's the maximum limit for the
598          * WaitForMultipleObjects() call.
599          */
600         if (numWorkers <= 0
601 #ifdef WIN32
602                 || numWorkers > MAXIMUM_WAIT_OBJECTS
603 #endif
604                 )
605                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
606
607         /* Parallel backup only in the directory archive format so far */
608         if (archiveFormat != archDirectory && numWorkers > 1)
609                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
610
611         /* Open the output file */
612         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
613                                                  setupDumpWorker);
614
615         /* Register the cleanup hook */
616         on_exit_close_archive(fout);
617
618         if (fout == NULL)
619                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
620
621         /* Let the archiver know how noisy to be */
622         fout->verbose = g_verbose;
623
624         /*
625          * We allow the server to be back to 7.0, and up to any minor release of
626          * our own major version.  (See also version check in pg_dumpall.c.)
627          */
628         fout->minRemoteVersion = 70000;
629         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
630
631         fout->numWorkers = numWorkers;
632
633         /*
634          * Open the database using the Archiver, so it knows about it. Errors mean
635          * death.
636          */
637         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
638         setup_connection(fout, dumpencoding, use_role);
639
640         /*
641          * Disable security label support if server version < v9.1.x (prevents
642          * access to nonexistent pg_seclabel catalog)
643          */
644         if (fout->remoteVersion < 90100)
645                 no_security_labels = 1;
646
647         /*
648          * When running against 9.0 or later, check if we are in recovery mode,
649          * which means we are on a hot standby.
650          */
651         if (fout->remoteVersion >= 90000)
652         {
653                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
654
655                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
656                 {
657                         /*
658                          * On hot standby slaves, never try to dump unlogged table data,
659                          * since it will just throw an error.
660                          */
661                         no_unlogged_table_data = true;
662                 }
663                 PQclear(res);
664         }
665
666         /* Select the appropriate subquery to convert user IDs to names */
667         if (fout->remoteVersion >= 80100)
668                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
669         else if (fout->remoteVersion >= 70300)
670                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
671         else
672                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
673
674         /* check the version for the synchronized snapshots feature */
675         if (numWorkers > 1 && fout->remoteVersion < 90200
676                 && !no_synchronized_snapshots)
677                 exit_horribly(NULL,
678                           "No synchronized snapshots available in this server version.\n"
679                            "Run with --no-synchronized-snapshots instead if you do not\n"
680                                           "need synchronized snapshots.\n");
681
682         /* Find the last built-in OID, if needed */
683         if (fout->remoteVersion < 70300)
684         {
685                 if (fout->remoteVersion >= 70100)
686                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
687                                                                                                   PQdb(GetConnection(fout)));
688                 else
689                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
690                 if (g_verbose)
691                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
692         }
693
694         /* Expand schema selection patterns into OID lists */
695         if (schema_include_patterns.head != NULL)
696         {
697                 expand_schema_name_patterns(fout, &schema_include_patterns,
698                                                                         &schema_include_oids);
699                 if (schema_include_oids.head == NULL)
700                         exit_horribly(NULL, "No matching schemas were found\n");
701         }
702         expand_schema_name_patterns(fout, &schema_exclude_patterns,
703                                                                 &schema_exclude_oids);
704         /* non-matching exclusion patterns aren't an error */
705
706         /* Expand table selection patterns into OID lists */
707         if (table_include_patterns.head != NULL)
708         {
709                 expand_table_name_patterns(fout, &table_include_patterns,
710                                                                    &table_include_oids);
711                 if (table_include_oids.head == NULL)
712                         exit_horribly(NULL, "No matching tables were found\n");
713         }
714         expand_table_name_patterns(fout, &table_exclude_patterns,
715                                                            &table_exclude_oids);
716
717         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
718                                                            &tabledata_exclude_oids);
719
720         /* non-matching exclusion patterns aren't an error */
721
722         /*
723          * Dumping blobs is now default unless we saw an inclusion switch or -s
724          * ... but even if we did see one of these, -b turns it back on.
725          */
726         if (include_everything && !schemaOnly)
727                 outputBlobs = true;
728
729         /*
730          * Now scan the database and create DumpableObject structs for all the
731          * objects we intend to dump.
732          */
733         tblinfo = getSchemaData(fout, &numTables);
734
735         if (fout->remoteVersion < 80400)
736                 guessConstraintInheritance(tblinfo, numTables);
737
738         if (!schemaOnly)
739         {
740                 getTableData(tblinfo, numTables, oids);
741                 buildMatViewRefreshDependencies(fout);
742                 if (dataOnly)
743                         getTableDataFKConstraints();
744         }
745
746         if (outputBlobs)
747                 getBlobs(fout);
748
749         /*
750          * Collect dependency data to assist in ordering the objects.
751          */
752         getDependencies(fout);
753
754         /* Lastly, create dummy objects to represent the section boundaries */
755         boundaryObjs = createBoundaryObjects();
756
757         /* Get pointers to all the known DumpableObjects */
758         getDumpableObjects(&dobjs, &numObjs);
759
760         /*
761          * Add dummy dependencies to enforce the dump section ordering.
762          */
763         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
764
765         /*
766          * Sort the objects into a safe dump order (no forward references).
767          *
768          * In 7.3 or later, we can rely on dependency information to help us
769          * determine a safe order, so the initial sort is mostly for cosmetic
770          * purposes: we sort by name to ensure that logically identical schemas
771          * will dump identically.  Before 7.3 we don't have dependencies and we
772          * use OID ordering as an (unreliable) guide to creation order.
773          */
774         if (fout->remoteVersion >= 70300)
775                 sortDumpableObjectsByTypeName(dobjs, numObjs);
776         else
777                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
778
779         /* If we do a parallel dump, we want the largest tables to go first */
780         if (archiveFormat == archDirectory && numWorkers > 1)
781                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
782
783         sortDumpableObjects(dobjs, numObjs,
784                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
785
786         /*
787          * Create archive TOC entries for all the objects to be dumped, in a safe
788          * order.
789          */
790
791         /* First the special ENCODING and STDSTRINGS entries. */
792         dumpEncoding(fout);
793         dumpStdStrings(fout);
794
795         /* The database item is always next, unless we don't want it at all */
796         if (include_everything && !dataOnly)
797                 dumpDatabase(fout);
798
799         /* Now the rearrangeable objects. */
800         for (i = 0; i < numObjs; i++)
801                 dumpDumpableObject(fout, dobjs[i]);
802
803         /*
804          * Set up options info to ensure we dump what we want.
805          */
806         ropt = NewRestoreOptions();
807         ropt->filename = filename;
808         ropt->dropSchema = outputClean;
809         ropt->dataOnly = dataOnly;
810         ropt->schemaOnly = schemaOnly;
811         ropt->dumpSections = dumpSections;
812         ropt->aclsSkip = aclsSkip;
813         ropt->superuser = outputSuperuser;
814         ropt->createDB = outputCreateDB;
815         ropt->noOwner = outputNoOwner;
816         ropt->noTablespace = outputNoTablespaces;
817         ropt->disable_triggers = disable_triggers;
818         ropt->use_setsessauth = use_setsessauth;
819
820         if (compressLevel == -1)
821                 ropt->compression = 0;
822         else
823                 ropt->compression = compressLevel;
824
825         ropt->suppressDumpWarnings = true;      /* We've already shown them */
826
827         SetArchiveRestoreOptions(fout, ropt);
828
829         /*
830          * The archive's TOC entries are now marked as to which ones will actually
831          * be output, so we can set up their dependency lists properly. This isn't
832          * necessary for plain-text output, though.
833          */
834         if (!plainText)
835                 BuildArchiveDependencies(fout);
836
837         /*
838          * And finally we can do the actual output.
839          *
840          * Note: for non-plain-text output formats, the output file is written
841          * inside CloseArchive().  This is, um, bizarre; but not worth changing
842          * right now.
843          */
844         if (plainText)
845                 RestoreArchive(fout);
846
847         CloseArchive(fout);
848
849         exit_nicely(0);
850 }
851
852
853 static void
854 help(const char *progname)
855 {
856         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
857         printf(_("Usage:\n"));
858         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
859
860         printf(_("\nGeneral options:\n"));
861         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
862         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
863                          "                               plain text (default))\n"));
864         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
865         printf(_("  -v, --verbose                verbose mode\n"));
866         printf(_("  -V, --version                output version information, then exit\n"));
867         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
868         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
869         printf(_("  -?, --help                   show this help, then exit\n"));
870
871         printf(_("\nOptions controlling the output content:\n"));
872         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
873         printf(_("  -b, --blobs                  include large objects in dump\n"));
874         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
875         printf(_("  -C, --create                 include commands to create database in dump\n"));
876         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
877         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
878         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
879         printf(_("  -o, --oids                   include OIDs in dump\n"));
880         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
881                          "                               plain-text format\n"));
882         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
883         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
884         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
885         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
886         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
887         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
888         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
889         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
890         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
891         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
892         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
893         printf(_("  --no-security-labels         do not dump security label assignments\n"));
894         printf(_("  --no-synchronized-snapshots parallel processes should not use synchronized snapshots\n"));
895         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
896         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
897         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
898         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
899         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
900         printf(_("  --use-set-session-authorization\n"
901                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
902                          "                               ALTER OWNER commands to set ownership\n"));
903
904         printf(_("\nConnection options:\n"));
905         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
906         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
907         printf(_("  -p, --port=PORT          database server port number\n"));
908         printf(_("  -U, --username=NAME      connect as specified database user\n"));
909         printf(_("  -w, --no-password        never prompt for password\n"));
910         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
911         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
912
913         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
914                          "variable value is used.\n\n"));
915         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
916 }
917
918 static void
919 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
920 {
921         PGconn     *conn = GetConnection(AH);
922         const char *std_strings;
923
924         /*
925          * Set the client encoding if requested. If dumpencoding == NULL then
926          * either it hasn't been requested or we're a cloned connection and then
927          * this has already been set in CloneArchive according to the original
928          * connection encoding.
929          */
930         if (dumpencoding)
931         {
932                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
933                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
934                                                   dumpencoding);
935         }
936
937         /*
938          * Get the active encoding and the standard_conforming_strings setting, so
939          * we know how to escape strings.
940          */
941         AH->encoding = PQclientEncoding(conn);
942
943         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
944         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
945
946         /* Set the role if requested */
947         if (!use_role && AH->use_role)
948                 use_role = AH->use_role;
949
950         /* Set the role if requested */
951         if (use_role && AH->remoteVersion >= 80100)
952         {
953                 PQExpBuffer query = createPQExpBuffer();
954
955                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
956                 ExecuteSqlStatement(AH, query->data);
957                 destroyPQExpBuffer(query);
958
959                 /* save this for later use on parallel connections */
960                 if (!AH->use_role)
961                         AH->use_role = strdup(use_role);
962         }
963
964         /* Set the datestyle to ISO to ensure the dump's portability */
965         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
966
967         /* Likewise, avoid using sql_standard intervalstyle */
968         if (AH->remoteVersion >= 80400)
969                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
970
971         /*
972          * If supported, set extra_float_digits so that we can dump float data
973          * exactly (given correctly implemented float I/O code, anyway)
974          */
975         if (AH->remoteVersion >= 90000)
976                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
977         else if (AH->remoteVersion >= 70400)
978                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
979
980         /*
981          * If synchronized scanning is supported, disable it, to prevent
982          * unpredictable changes in row ordering across a dump and reload.
983          */
984         if (AH->remoteVersion >= 80300)
985                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
986
987         /*
988          * Disable timeouts if supported.
989          */
990         if (AH->remoteVersion >= 70300)
991                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
992         if (AH->remoteVersion >= 90300)
993                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
994
995         /*
996          * Quote all identifiers, if requested.
997          */
998         if (quote_all_identifiers && AH->remoteVersion >= 90100)
999                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1000
1001         /*
1002          * Start transaction-snapshot mode transaction to dump consistent data.
1003          */
1004         ExecuteSqlStatement(AH, "BEGIN");
1005         if (AH->remoteVersion >= 90100)
1006         {
1007                 if (serializable_deferrable)
1008                         ExecuteSqlStatement(AH,
1009                                                                 "SET TRANSACTION ISOLATION LEVEL "
1010                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1011                 else
1012                         ExecuteSqlStatement(AH,
1013                                                                 "SET TRANSACTION ISOLATION LEVEL "
1014                                                                 "REPEATABLE READ, READ ONLY");
1015         }
1016         else if (AH->remoteVersion >= 70400)
1017         {
1018                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1019                 ExecuteSqlStatement(AH,
1020                                                         "SET TRANSACTION ISOLATION LEVEL "
1021                                                         "SERIALIZABLE READ ONLY");
1022         }
1023         else
1024                 ExecuteSqlStatement(AH,
1025                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1026
1027
1028
1029         if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
1030         {
1031                 if (AH->sync_snapshot_id)
1032                 {
1033                         PQExpBuffer query = createPQExpBuffer();
1034
1035                         appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1036                         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1037                         destroyPQExpBuffer(query);
1038                 }
1039                 else
1040                         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1041         }
1042 }
1043
1044 static void
1045 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
1046 {
1047         setup_connection(AHX, NULL, NULL);
1048 }
1049
1050 static char *
1051 get_synchronized_snapshot(Archive *fout)
1052 {
1053         char       *query = "SELECT pg_export_snapshot()";
1054         char       *result;
1055         PGresult   *res;
1056
1057         res = ExecuteSqlQueryForSingleRow(fout, query);
1058         result = strdup(PQgetvalue(res, 0, 0));
1059         PQclear(res);
1060
1061         return result;
1062 }
1063
1064 static ArchiveFormat
1065 parseArchiveFormat(const char *format, ArchiveMode *mode)
1066 {
1067         ArchiveFormat archiveFormat;
1068
1069         *mode = archModeWrite;
1070
1071         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1072         {
1073                 /* This is used by pg_dumpall, and is not documented */
1074                 archiveFormat = archNull;
1075                 *mode = archModeAppend;
1076         }
1077         else if (pg_strcasecmp(format, "c") == 0)
1078                 archiveFormat = archCustom;
1079         else if (pg_strcasecmp(format, "custom") == 0)
1080                 archiveFormat = archCustom;
1081         else if (pg_strcasecmp(format, "d") == 0)
1082                 archiveFormat = archDirectory;
1083         else if (pg_strcasecmp(format, "directory") == 0)
1084                 archiveFormat = archDirectory;
1085         else if (pg_strcasecmp(format, "p") == 0)
1086                 archiveFormat = archNull;
1087         else if (pg_strcasecmp(format, "plain") == 0)
1088                 archiveFormat = archNull;
1089         else if (pg_strcasecmp(format, "t") == 0)
1090                 archiveFormat = archTar;
1091         else if (pg_strcasecmp(format, "tar") == 0)
1092                 archiveFormat = archTar;
1093         else
1094                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1095         return archiveFormat;
1096 }
1097
1098 /*
1099  * Find the OIDs of all schemas matching the given list of patterns,
1100  * and append them to the given OID list.
1101  */
1102 static void
1103 expand_schema_name_patterns(Archive *fout,
1104                                                         SimpleStringList *patterns,
1105                                                         SimpleOidList *oids)
1106 {
1107         PQExpBuffer query;
1108         PGresult   *res;
1109         SimpleStringListCell *cell;
1110         int                     i;
1111
1112         if (patterns->head == NULL)
1113                 return;                                 /* nothing to do */
1114
1115         if (fout->remoteVersion < 70300)
1116                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1117
1118         query = createPQExpBuffer();
1119
1120         /*
1121          * We use UNION ALL rather than UNION; this might sometimes result in
1122          * duplicate entries in the OID list, but we don't care.
1123          */
1124
1125         for (cell = patterns->head; cell; cell = cell->next)
1126         {
1127                 if (cell != patterns->head)
1128                         appendPQExpBuffer(query, "UNION ALL\n");
1129                 appendPQExpBuffer(query,
1130                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1131                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1132                                                           false, NULL, "n.nspname", NULL, NULL);
1133         }
1134
1135         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1136
1137         for (i = 0; i < PQntuples(res); i++)
1138         {
1139                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1140         }
1141
1142         PQclear(res);
1143         destroyPQExpBuffer(query);
1144 }
1145
1146 /*
1147  * Find the OIDs of all tables matching the given list of patterns,
1148  * and append them to the given OID list.
1149  */
1150 static void
1151 expand_table_name_patterns(Archive *fout,
1152                                                    SimpleStringList *patterns, SimpleOidList *oids)
1153 {
1154         PQExpBuffer query;
1155         PGresult   *res;
1156         SimpleStringListCell *cell;
1157         int                     i;
1158
1159         if (patterns->head == NULL)
1160                 return;                                 /* nothing to do */
1161
1162         query = createPQExpBuffer();
1163
1164         /*
1165          * We use UNION ALL rather than UNION; this might sometimes result in
1166          * duplicate entries in the OID list, but we don't care.
1167          */
1168
1169         for (cell = patterns->head; cell; cell = cell->next)
1170         {
1171                 if (cell != patterns->head)
1172                         appendPQExpBuffer(query, "UNION ALL\n");
1173                 appendPQExpBuffer(query,
1174                                                   "SELECT c.oid"
1175                                                   "\nFROM pg_catalog.pg_class c"
1176                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1177                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1178                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1179                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1180                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1181                                                           false, "n.nspname", "c.relname", NULL,
1182                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1183         }
1184
1185         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1186
1187         for (i = 0; i < PQntuples(res); i++)
1188         {
1189                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1190         }
1191
1192         PQclear(res);
1193         destroyPQExpBuffer(query);
1194 }
1195
1196 /*
1197  * selectDumpableNamespace: policy-setting subroutine
1198  *              Mark a namespace as to be dumped or not
1199  */
1200 static void
1201 selectDumpableNamespace(NamespaceInfo *nsinfo)
1202 {
1203         /*
1204          * If specific tables are being dumped, do not dump any complete
1205          * namespaces. If specific namespaces are being dumped, dump just those
1206          * namespaces. Otherwise, dump all non-system namespaces.
1207          */
1208         if (table_include_oids.head != NULL)
1209                 nsinfo->dobj.dump = false;
1210         else if (schema_include_oids.head != NULL)
1211                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1212                                                                                                    nsinfo->dobj.catId.oid);
1213         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1214                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1215                 nsinfo->dobj.dump = false;
1216         else
1217                 nsinfo->dobj.dump = true;
1218
1219         /*
1220          * In any case, a namespace can be excluded by an exclusion switch
1221          */
1222         if (nsinfo->dobj.dump &&
1223                 simple_oid_list_member(&schema_exclude_oids,
1224                                                            nsinfo->dobj.catId.oid))
1225                 nsinfo->dobj.dump = false;
1226 }
1227
1228 /*
1229  * selectDumpableTable: policy-setting subroutine
1230  *              Mark a table as to be dumped or not
1231  */
1232 static void
1233 selectDumpableTable(TableInfo *tbinfo)
1234 {
1235         /*
1236          * If specific tables are being dumped, dump just those tables; else, dump
1237          * according to the parent namespace's dump flag.
1238          */
1239         if (table_include_oids.head != NULL)
1240                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1241                                                                                                    tbinfo->dobj.catId.oid);
1242         else
1243                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1244
1245         /*
1246          * In any case, a table can be excluded by an exclusion switch
1247          */
1248         if (tbinfo->dobj.dump &&
1249                 simple_oid_list_member(&table_exclude_oids,
1250                                                            tbinfo->dobj.catId.oid))
1251                 tbinfo->dobj.dump = false;
1252 }
1253
1254 /*
1255  * selectDumpableType: policy-setting subroutine
1256  *              Mark a type as to be dumped or not
1257  *
1258  * If it's a table's rowtype or an autogenerated array type, we also apply a
1259  * special type code to facilitate sorting into the desired order.      (We don't
1260  * want to consider those to be ordinary types because that would bring tables
1261  * up into the datatype part of the dump order.)  We still set the object's
1262  * dump flag; that's not going to cause the dummy type to be dumped, but we
1263  * need it so that casts involving such types will be dumped correctly -- see
1264  * dumpCast.  This means the flag should be set the same as for the underlying
1265  * object (the table or base type).
1266  */
1267 static void
1268 selectDumpableType(TypeInfo *tyinfo)
1269 {
1270         /* skip complex types, except for standalone composite types */
1271         if (OidIsValid(tyinfo->typrelid) &&
1272                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1273         {
1274                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1275
1276                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1277                 if (tytable != NULL)
1278                         tyinfo->dobj.dump = tytable->dobj.dump;
1279                 else
1280                         tyinfo->dobj.dump = false;
1281                 return;
1282         }
1283
1284         /* skip auto-generated array types */
1285         if (tyinfo->isArray)
1286         {
1287                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1288
1289                 /*
1290                  * Fall through to set the dump flag; we assume that the subsequent
1291                  * rules will do the same thing as they would for the array's base
1292                  * type.  (We cannot reliably look up the base type here, since
1293                  * getTypes may not have processed it yet.)
1294                  */
1295         }
1296
1297         /* dump only types in dumpable namespaces */
1298         if (!tyinfo->dobj.namespace->dobj.dump)
1299                 tyinfo->dobj.dump = false;
1300
1301         /* skip undefined placeholder types */
1302         else if (!tyinfo->isDefined)
1303                 tyinfo->dobj.dump = false;
1304
1305         else
1306                 tyinfo->dobj.dump = true;
1307 }
1308
1309 /*
1310  * selectDumpableDefaultACL: policy-setting subroutine
1311  *              Mark a default ACL as to be dumped or not
1312  *
1313  * For per-schema default ACLs, dump if the schema is to be dumped.
1314  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1315  * and aclsSkip are checked separately.
1316  */
1317 static void
1318 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1319 {
1320         if (dinfo->dobj.namespace)
1321                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1322         else
1323                 dinfo->dobj.dump = include_everything;
1324 }
1325
1326 /*
1327  * selectDumpableExtension: policy-setting subroutine
1328  *              Mark an extension as to be dumped or not
1329  *
1330  * Normally, we dump all extensions, or none of them if include_everything
1331  * is false (i.e., a --schema or --table switch was given).  However, in
1332  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1333  * assume those will already be installed in the target database.  We identify
1334  * such extensions by their having OIDs in the range reserved for initdb.
1335  */
1336 static void
1337 selectDumpableExtension(ExtensionInfo *extinfo)
1338 {
1339         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1340                 extinfo->dobj.dump = false;
1341         else
1342                 extinfo->dobj.dump = include_everything;
1343 }
1344
1345 /*
1346  * selectDumpableObject: policy-setting subroutine
1347  *              Mark a generic dumpable object as to be dumped or not
1348  *
1349  * Use this only for object types without a special-case routine above.
1350  */
1351 static void
1352 selectDumpableObject(DumpableObject *dobj)
1353 {
1354         /*
1355          * Default policy is to dump if parent namespace is dumpable, or always
1356          * for non-namespace-associated items.
1357          */
1358         if (dobj->namespace)
1359                 dobj->dump = dobj->namespace->dobj.dump;
1360         else
1361                 dobj->dump = true;
1362 }
1363
1364 /*
1365  *      Dump a table's contents for loading using the COPY command
1366  *      - this routine is called by the Archiver when it wants the table
1367  *        to be dumped.
1368  */
1369
1370 static int
1371 dumpTableData_copy(Archive *fout, void *dcontext)
1372 {
1373         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1374         TableInfo  *tbinfo = tdinfo->tdtable;
1375         const char *classname = tbinfo->dobj.name;
1376         const bool      hasoids = tbinfo->hasoids;
1377         const bool      oids = tdinfo->oids;
1378         PQExpBuffer q = createPQExpBuffer();
1379
1380         /*
1381          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1382          * which uses it already.
1383          */
1384         PQExpBuffer clistBuf = createPQExpBuffer();
1385         PGconn     *conn = GetConnection(fout);
1386         PGresult   *res;
1387         int                     ret;
1388         char       *copybuf;
1389         const char *column_list;
1390
1391         if (g_verbose)
1392                 write_msg(NULL, "dumping contents of table %s\n", classname);
1393
1394         /*
1395          * Make sure we are in proper schema.  We will qualify the table name
1396          * below anyway (in case its name conflicts with a pg_catalog table); but
1397          * this ensures reproducible results in case the table contains regproc,
1398          * regclass, etc columns.
1399          */
1400         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1401
1402         /*
1403          * If possible, specify the column list explicitly so that we have no
1404          * possibility of retrieving data in the wrong column order.  (The default
1405          * column ordering of COPY will not be what we want in certain corner
1406          * cases involving ADD COLUMN and inheritance.)
1407          */
1408         if (fout->remoteVersion >= 70300)
1409                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1410         else
1411                 column_list = "";               /* can't select columns in COPY */
1412
1413         if (oids && hasoids)
1414         {
1415                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1416                                                   fmtQualifiedId(fout->remoteVersion,
1417                                                                                  tbinfo->dobj.namespace->dobj.name,
1418                                                                                  classname),
1419                                                   column_list);
1420         }
1421         else if (tdinfo->filtercond)
1422         {
1423                 /* Note: this syntax is only supported in 8.2 and up */
1424                 appendPQExpBufferStr(q, "COPY (SELECT ");
1425                 /* klugery to get rid of parens in column list */
1426                 if (strlen(column_list) > 2)
1427                 {
1428                         appendPQExpBufferStr(q, column_list + 1);
1429                         q->data[q->len - 1] = ' ';
1430                 }
1431                 else
1432                         appendPQExpBufferStr(q, "* ");
1433                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1434                                                   fmtQualifiedId(fout->remoteVersion,
1435                                                                                  tbinfo->dobj.namespace->dobj.name,
1436                                                                                  classname),
1437                                                   tdinfo->filtercond);
1438         }
1439         else
1440         {
1441                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1442                                                   fmtQualifiedId(fout->remoteVersion,
1443                                                                                  tbinfo->dobj.namespace->dobj.name,
1444                                                                                  classname),
1445                                                   column_list);
1446         }
1447         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1448         PQclear(res);
1449         destroyPQExpBuffer(clistBuf);
1450
1451         for (;;)
1452         {
1453                 ret = PQgetCopyData(conn, &copybuf, 0);
1454
1455                 if (ret < 0)
1456                         break;                          /* done or error */
1457
1458                 if (copybuf)
1459                 {
1460                         WriteData(fout, copybuf, ret);
1461                         PQfreemem(copybuf);
1462                 }
1463
1464                 /* ----------
1465                  * THROTTLE:
1466                  *
1467                  * There was considerable discussion in late July, 2000 regarding
1468                  * slowing down pg_dump when backing up large tables. Users with both
1469                  * slow & fast (multi-processor) machines experienced performance
1470                  * degradation when doing a backup.
1471                  *
1472                  * Initial attempts based on sleeping for a number of ms for each ms
1473                  * of work were deemed too complex, then a simple 'sleep in each loop'
1474                  * implementation was suggested. The latter failed because the loop
1475                  * was too tight. Finally, the following was implemented:
1476                  *
1477                  * If throttle is non-zero, then
1478                  *              See how long since the last sleep.
1479                  *              Work out how long to sleep (based on ratio).
1480                  *              If sleep is more than 100ms, then
1481                  *                      sleep
1482                  *                      reset timer
1483                  *              EndIf
1484                  * EndIf
1485                  *
1486                  * where the throttle value was the number of ms to sleep per ms of
1487                  * work. The calculation was done in each loop.
1488                  *
1489                  * Most of the hard work is done in the backend, and this solution
1490                  * still did not work particularly well: on slow machines, the ratio
1491                  * was 50:1, and on medium paced machines, 1:1, and on fast
1492                  * multi-processor machines, it had little or no effect, for reasons
1493                  * that were unclear.
1494                  *
1495                  * Further discussion ensued, and the proposal was dropped.
1496                  *
1497                  * For those people who want this feature, it can be implemented using
1498                  * gettimeofday in each loop, calculating the time since last sleep,
1499                  * multiplying that by the sleep ratio, then if the result is more
1500                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1501                  * function to sleep for a subsecond period ie.
1502                  *
1503                  * select(0, NULL, NULL, NULL, &tvi);
1504                  *
1505                  * This will return after the interval specified in the structure tvi.
1506                  * Finally, call gettimeofday again to save the 'last sleep time'.
1507                  * ----------
1508                  */
1509         }
1510         archprintf(fout, "\\.\n\n\n");
1511
1512         if (ret == -2)
1513         {
1514                 /* copy data transfer failed */
1515                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1516                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1517                 write_msg(NULL, "The command was: %s\n", q->data);
1518                 exit_nicely(1);
1519         }
1520
1521         /* Check command status and return to normal libpq state */
1522         res = PQgetResult(conn);
1523         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1524         {
1525                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1526                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1527                 write_msg(NULL, "The command was: %s\n", q->data);
1528                 exit_nicely(1);
1529         }
1530         PQclear(res);
1531
1532         destroyPQExpBuffer(q);
1533         return 1;
1534 }
1535
1536 /*
1537  * Dump table data using INSERT commands.
1538  *
1539  * Caution: when we restore from an archive file direct to database, the
1540  * INSERT commands emitted by this function have to be parsed by
1541  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1542  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1543  */
1544 static int
1545 dumpTableData_insert(Archive *fout, void *dcontext)
1546 {
1547         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1548         TableInfo  *tbinfo = tdinfo->tdtable;
1549         const char *classname = tbinfo->dobj.name;
1550         PQExpBuffer q = createPQExpBuffer();
1551         PGresult   *res;
1552         int                     tuple;
1553         int                     nfields;
1554         int                     field;
1555
1556         /*
1557          * Make sure we are in proper schema.  We will qualify the table name
1558          * below anyway (in case its name conflicts with a pg_catalog table); but
1559          * this ensures reproducible results in case the table contains regproc,
1560          * regclass, etc columns.
1561          */
1562         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1563
1564         if (fout->remoteVersion >= 70100)
1565         {
1566                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1567                                                   "SELECT * FROM ONLY %s",
1568                                                   fmtQualifiedId(fout->remoteVersion,
1569                                                                                  tbinfo->dobj.namespace->dobj.name,
1570                                                                                  classname));
1571         }
1572         else
1573         {
1574                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1575                                                   "SELECT * FROM %s",
1576                                                   fmtQualifiedId(fout->remoteVersion,
1577                                                                                  tbinfo->dobj.namespace->dobj.name,
1578                                                                                  classname));
1579         }
1580         if (tdinfo->filtercond)
1581                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1582
1583         ExecuteSqlStatement(fout, q->data);
1584
1585         while (1)
1586         {
1587                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1588                                                           PGRES_TUPLES_OK);
1589                 nfields = PQnfields(res);
1590                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1591                 {
1592                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1593                         if (nfields == 0)
1594                         {
1595                                 /* corner case for zero-column table */
1596                                 archprintf(fout, "DEFAULT VALUES;\n");
1597                                 continue;
1598                         }
1599                         if (column_inserts)
1600                         {
1601                                 resetPQExpBuffer(q);
1602                                 appendPQExpBuffer(q, "(");
1603                                 for (field = 0; field < nfields; field++)
1604                                 {
1605                                         if (field > 0)
1606                                                 appendPQExpBuffer(q, ", ");
1607                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1608                                 }
1609                                 appendPQExpBuffer(q, ") ");
1610                                 archputs(q->data, fout);
1611                         }
1612                         archprintf(fout, "VALUES (");
1613                         for (field = 0; field < nfields; field++)
1614                         {
1615                                 if (field > 0)
1616                                         archprintf(fout, ", ");
1617                                 if (PQgetisnull(res, tuple, field))
1618                                 {
1619                                         archprintf(fout, "NULL");
1620                                         continue;
1621                                 }
1622
1623                                 /* XXX This code is partially duplicated in ruleutils.c */
1624                                 switch (PQftype(res, field))
1625                                 {
1626                                         case INT2OID:
1627                                         case INT4OID:
1628                                         case INT8OID:
1629                                         case OIDOID:
1630                                         case FLOAT4OID:
1631                                         case FLOAT8OID:
1632                                         case NUMERICOID:
1633                                                 {
1634                                                         /*
1635                                                          * These types are printed without quotes unless
1636                                                          * they contain values that aren't accepted by the
1637                                                          * scanner unquoted (e.g., 'NaN').      Note that
1638                                                          * strtod() and friends might accept NaN, so we
1639                                                          * can't use that to test.
1640                                                          *
1641                                                          * In reality we only need to defend against
1642                                                          * infinity and NaN, so we need not get too crazy
1643                                                          * about pattern matching here.
1644                                                          */
1645                                                         const char *s = PQgetvalue(res, tuple, field);
1646
1647                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1648                                                                 archprintf(fout, "%s", s);
1649                                                         else
1650                                                                 archprintf(fout, "'%s'", s);
1651                                                 }
1652                                                 break;
1653
1654                                         case BITOID:
1655                                         case VARBITOID:
1656                                                 archprintf(fout, "B'%s'",
1657                                                                    PQgetvalue(res, tuple, field));
1658                                                 break;
1659
1660                                         case BOOLOID:
1661                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1662                                                         archprintf(fout, "true");
1663                                                 else
1664                                                         archprintf(fout, "false");
1665                                                 break;
1666
1667                                         default:
1668                                                 /* All other types are printed as string literals. */
1669                                                 resetPQExpBuffer(q);
1670                                                 appendStringLiteralAH(q,
1671                                                                                           PQgetvalue(res, tuple, field),
1672                                                                                           fout);
1673                                                 archputs(q->data, fout);
1674                                                 break;
1675                                 }
1676                         }
1677                         archprintf(fout, ");\n");
1678                 }
1679
1680                 if (PQntuples(res) <= 0)
1681                 {
1682                         PQclear(res);
1683                         break;
1684                 }
1685                 PQclear(res);
1686         }
1687
1688         archprintf(fout, "\n\n");
1689
1690         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1691
1692         destroyPQExpBuffer(q);
1693         return 1;
1694 }
1695
1696
1697 /*
1698  * dumpTableData -
1699  *        dump the contents of a single table
1700  *
1701  * Actually, this just makes an ArchiveEntry for the table contents.
1702  */
1703 static void
1704 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1705 {
1706         TableInfo  *tbinfo = tdinfo->tdtable;
1707         PQExpBuffer copyBuf = createPQExpBuffer();
1708         PQExpBuffer clistBuf = createPQExpBuffer();
1709         DataDumperPtr dumpFn;
1710         char       *copyStmt;
1711
1712         if (!dump_inserts)
1713         {
1714                 /* Dump/restore using COPY */
1715                 dumpFn = dumpTableData_copy;
1716                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1717                 appendPQExpBuffer(copyBuf, "COPY %s ",
1718                                                   fmtId(tbinfo->dobj.name));
1719                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1720                                                   fmtCopyColumnList(tbinfo, clistBuf),
1721                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1722                 copyStmt = copyBuf->data;
1723         }
1724         else
1725         {
1726                 /* Restore using INSERT */
1727                 dumpFn = dumpTableData_insert;
1728                 copyStmt = NULL;
1729         }
1730
1731         /*
1732          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1733          * dependency on its table as "special" and pass it to ArchiveEntry now.
1734          * See comments for BuildArchiveDependencies.
1735          */
1736         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1737                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1738                                  NULL, tbinfo->rolname,
1739                                  false, "TABLE DATA", SECTION_DATA,
1740                                  "", "", copyStmt,
1741                                  &(tbinfo->dobj.dumpId), 1,
1742                                  dumpFn, tdinfo);
1743
1744         destroyPQExpBuffer(copyBuf);
1745         destroyPQExpBuffer(clistBuf);
1746 }
1747
1748 /*
1749  * refreshMatViewData -
1750  *        load or refresh the contents of a single materialized view
1751  *
1752  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1753  * statement.
1754  */
1755 static void
1756 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1757 {
1758         TableInfo  *tbinfo = tdinfo->tdtable;
1759         PQExpBuffer q;
1760
1761         /* If the materialized view is not flagged as scannable, skip this. */
1762         if (!tbinfo->isscannable)
1763                 return;
1764
1765         q = createPQExpBuffer();
1766
1767         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1768                                           fmtId(tbinfo->dobj.name));
1769
1770         ArchiveEntry(fout,
1771                                  tdinfo->dobj.catId,    /* catalog ID */
1772                                  tdinfo->dobj.dumpId,   /* dump ID */
1773                                  tbinfo->dobj.name,             /* Name */
1774                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1775                                  NULL,                  /* Tablespace */
1776                                  tbinfo->rolname,               /* Owner */
1777                                  false,                 /* with oids */
1778                                  "MATERIALIZED VIEW DATA",              /* Desc */
1779                                  SECTION_POST_DATA,             /* Section */
1780                                  q->data,               /* Create */
1781                                  "",                    /* Del */
1782                                  NULL,                  /* Copy */
1783                                  tdinfo->dobj.dependencies,             /* Deps */
1784                                  tdinfo->dobj.nDeps,    /* # Deps */
1785                                  NULL,                  /* Dumper */
1786                                  NULL);                 /* Dumper Arg */
1787
1788         destroyPQExpBuffer(q);
1789 }
1790
1791 /*
1792  * getTableData -
1793  *        set up dumpable objects representing the contents of tables
1794  */
1795 static void
1796 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1797 {
1798         int                     i;
1799
1800         for (i = 0; i < numTables; i++)
1801         {
1802                 if (tblinfo[i].dobj.dump)
1803                         makeTableDataInfo(&(tblinfo[i]), oids);
1804         }
1805 }
1806
1807 /*
1808  * Make a dumpable object for the data of this specific table
1809  *
1810  * Note: we make a TableDataInfo if and only if we are going to dump the
1811  * table data; the "dump" flag in such objects isn't used.
1812  */
1813 static void
1814 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1815 {
1816         TableDataInfo *tdinfo;
1817
1818         /*
1819          * Nothing to do if we already decided to dump the table.  This will
1820          * happen for "config" tables.
1821          */
1822         if (tbinfo->dataObj != NULL)
1823                 return;
1824
1825         /* Skip VIEWs (no data to dump) */
1826         if (tbinfo->relkind == RELKIND_VIEW)
1827                 return;
1828         /* Skip FOREIGN TABLEs (no data to dump) */
1829         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1830                 return;
1831
1832         /* Don't dump data in unlogged tables, if so requested */
1833         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1834                 no_unlogged_table_data)
1835                 return;
1836
1837         /* Check that the data is not explicitly excluded */
1838         if (simple_oid_list_member(&tabledata_exclude_oids,
1839                                                            tbinfo->dobj.catId.oid))
1840                 return;
1841
1842         /* OK, let's dump it */
1843         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1844
1845         if (tbinfo->relkind == RELKIND_MATVIEW)
1846                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1847         else
1848                 tdinfo->dobj.objType = DO_TABLE_DATA;
1849
1850         /*
1851          * Note: use tableoid 0 so that this object won't be mistaken for
1852          * something that pg_depend entries apply to.
1853          */
1854         tdinfo->dobj.catId.tableoid = 0;
1855         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1856         AssignDumpId(&tdinfo->dobj);
1857         tdinfo->dobj.name = tbinfo->dobj.name;
1858         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1859         tdinfo->tdtable = tbinfo;
1860         tdinfo->oids = oids;
1861         tdinfo->filtercond = NULL;      /* might get set later */
1862         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1863
1864         tbinfo->dataObj = tdinfo;
1865 }
1866
1867 /*
1868  * The refresh for a materialized view must be dependent on the refresh for
1869  * any materialized view that this one is dependent on.
1870  *
1871  * This must be called after all the objects are created, but before they are
1872  * sorted.
1873  */
1874 static void
1875 buildMatViewRefreshDependencies(Archive *fout)
1876 {
1877         PQExpBuffer query;
1878         PGresult   *res;
1879         int                     ntups,
1880                                 i;
1881         int                     i_classid,
1882                                 i_objid,
1883                                 i_refobjid;
1884
1885         /* No Mat Views before 9.3. */
1886         if (fout->remoteVersion < 90300)
1887                 return;
1888
1889         /* Make sure we are in proper schema */
1890         selectSourceSchema(fout, "pg_catalog");
1891
1892         query = createPQExpBuffer();
1893
1894         appendPQExpBuffer(query, "with recursive w as "
1895                                           "( "
1896                                         "select d1.objid, d2.refobjid, c2.relkind as refrelkind "
1897                                           "from pg_depend d1 "
1898                                           "join pg_class c1 on c1.oid = d1.objid "
1899                                           "and c1.relkind = 'm' "
1900                                           "join pg_rewrite r1 on r1.ev_class = d1.objid "
1901                                   "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass "
1902                                           "and d2.objid = r1.oid "
1903                                           "and d2.refobjid <> d1.objid "
1904                                           "join pg_class c2 on c2.oid = d2.refobjid "
1905                                           "and c2.relkind in ('m','v') "
1906                                           "where d1.classid = 'pg_class'::regclass "
1907                                           "union "
1908                                           "select w.objid, d3.refobjid, c3.relkind "
1909                                           "from w "
1910                                           "join pg_rewrite r3 on r3.ev_class = w.refobjid "
1911                                   "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass "
1912                                           "and d3.objid = r3.oid "
1913                                           "and d3.refobjid <> w.refobjid "
1914                                           "join pg_class c3 on c3.oid = d3.refobjid "
1915                                           "and c3.relkind in ('m','v') "
1916                                           ") "
1917                           "select 'pg_class'::regclass::oid as classid, objid, refobjid "
1918                                           "from w "
1919                                           "where refrelkind = 'm'");
1920
1921         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1922
1923         ntups = PQntuples(res);
1924
1925         i_classid = PQfnumber(res, "classid");
1926         i_objid = PQfnumber(res, "objid");
1927         i_refobjid = PQfnumber(res, "refobjid");
1928
1929         for (i = 0; i < ntups; i++)
1930         {
1931                 CatalogId       objId;
1932                 CatalogId       refobjId;
1933                 DumpableObject *dobj;
1934                 DumpableObject *refdobj;
1935                 TableInfo  *tbinfo;
1936                 TableInfo  *reftbinfo;
1937
1938                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1939                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1940                 refobjId.tableoid = objId.tableoid;
1941                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1942
1943                 dobj = findObjectByCatalogId(objId);
1944                 if (dobj == NULL)
1945                         continue;
1946
1947                 Assert(dobj->objType == DO_TABLE);
1948                 tbinfo = (TableInfo *) dobj;
1949                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1950                 dobj = (DumpableObject *) tbinfo->dataObj;
1951                 if (dobj == NULL)
1952                         continue;
1953                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
1954
1955                 refdobj = findObjectByCatalogId(refobjId);
1956                 if (refdobj == NULL)
1957                         continue;
1958
1959                 Assert(refdobj->objType == DO_TABLE);
1960                 reftbinfo = (TableInfo *) refdobj;
1961                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
1962                 refdobj = (DumpableObject *) reftbinfo->dataObj;
1963                 if (refdobj == NULL)
1964                         continue;
1965                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
1966
1967                 addObjectDependency(dobj, refdobj->dumpId);
1968
1969                 if (!reftbinfo->isscannable)
1970                         tbinfo->isscannable = false;
1971         }
1972
1973         PQclear(res);
1974
1975         destroyPQExpBuffer(query);
1976 }
1977
1978 /*
1979  * getTableDataFKConstraints -
1980  *        add dump-order dependencies reflecting foreign key constraints
1981  *
1982  * This code is executed only in a data-only dump --- in schema+data dumps
1983  * we handle foreign key issues by not creating the FK constraints until
1984  * after the data is loaded.  In a data-only dump, however, we want to
1985  * order the table data objects in such a way that a table's referenced
1986  * tables are restored first.  (In the presence of circular references or
1987  * self-references this may be impossible; we'll detect and complain about
1988  * that during the dependency sorting step.)
1989  */
1990 static void
1991 getTableDataFKConstraints(void)
1992 {
1993         DumpableObject **dobjs;
1994         int                     numObjs;
1995         int                     i;
1996
1997         /* Search through all the dumpable objects for FK constraints */
1998         getDumpableObjects(&dobjs, &numObjs);
1999         for (i = 0; i < numObjs; i++)
2000         {
2001                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2002                 {
2003                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2004                         TableInfo  *ftable;
2005
2006                         /* Not interesting unless both tables are to be dumped */
2007                         if (cinfo->contable == NULL ||
2008                                 cinfo->contable->dataObj == NULL)
2009                                 continue;
2010                         ftable = findTableByOid(cinfo->confrelid);
2011                         if (ftable == NULL ||
2012                                 ftable->dataObj == NULL)
2013                                 continue;
2014
2015                         /*
2016                          * Okay, make referencing table's TABLE_DATA object depend on the
2017                          * referenced table's TABLE_DATA object.
2018                          */
2019                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2020                                                                 ftable->dataObj->dobj.dumpId);
2021                 }
2022         }
2023         free(dobjs);
2024 }
2025
2026
2027 /*
2028  * guessConstraintInheritance:
2029  *      In pre-8.4 databases, we can't tell for certain which constraints
2030  *      are inherited.  We assume a CHECK constraint is inherited if its name
2031  *      matches the name of any constraint in the parent.  Originally this code
2032  *      tried to compare the expression texts, but that can fail for various
2033  *      reasons --- for example, if the parent and child tables are in different
2034  *      schemas, reverse-listing of function calls may produce different text
2035  *      (schema-qualified or not) depending on search path.
2036  *
2037  *      In 8.4 and up we can rely on the conislocal field to decide which
2038  *      constraints must be dumped; much safer.
2039  *
2040  *      This function assumes all conislocal flags were initialized to TRUE.
2041  *      It clears the flag on anything that seems to be inherited.
2042  */
2043 static void
2044 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2045 {
2046         int                     i,
2047                                 j,
2048                                 k;
2049
2050         for (i = 0; i < numTables; i++)
2051         {
2052                 TableInfo  *tbinfo = &(tblinfo[i]);
2053                 int                     numParents;
2054                 TableInfo **parents;
2055                 TableInfo  *parent;
2056
2057                 /* Sequences and views never have parents */
2058                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2059                         tbinfo->relkind == RELKIND_VIEW)
2060                         continue;
2061
2062                 /* Don't bother computing anything for non-target tables, either */
2063                 if (!tbinfo->dobj.dump)
2064                         continue;
2065
2066                 numParents = tbinfo->numParents;
2067                 parents = tbinfo->parents;
2068
2069                 if (numParents == 0)
2070                         continue;                       /* nothing to see here, move along */
2071
2072                 /* scan for inherited CHECK constraints */
2073                 for (j = 0; j < tbinfo->ncheck; j++)
2074                 {
2075                         ConstraintInfo *constr;
2076
2077                         constr = &(tbinfo->checkexprs[j]);
2078
2079                         for (k = 0; k < numParents; k++)
2080                         {
2081                                 int                     l;
2082
2083                                 parent = parents[k];
2084                                 for (l = 0; l < parent->ncheck; l++)
2085                                 {
2086                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2087
2088                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2089                                         {
2090                                                 constr->conislocal = false;
2091                                                 break;
2092                                         }
2093                                 }
2094                                 if (!constr->conislocal)
2095                                         break;
2096                         }
2097                 }
2098         }
2099 }
2100
2101
2102 /*
2103  * dumpDatabase:
2104  *      dump the database definition
2105  */
2106 static void
2107 dumpDatabase(Archive *fout)
2108 {
2109         PQExpBuffer dbQry = createPQExpBuffer();
2110         PQExpBuffer delQry = createPQExpBuffer();
2111         PQExpBuffer creaQry = createPQExpBuffer();
2112         PGconn     *conn = GetConnection(fout);
2113         PGresult   *res;
2114         int                     i_tableoid,
2115                                 i_oid,
2116                                 i_dba,
2117                                 i_encoding,
2118                                 i_collate,
2119                                 i_ctype,
2120                                 i_frozenxid,
2121                                 i_tablespace;
2122         CatalogId       dbCatId;
2123         DumpId          dbDumpId;
2124         const char *datname,
2125                            *dba,
2126                            *encoding,
2127                            *collate,
2128                            *ctype,
2129                            *tablespace;
2130         uint32          frozenxid;
2131
2132         datname = PQdb(conn);
2133
2134         if (g_verbose)
2135                 write_msg(NULL, "saving database definition\n");
2136
2137         /* Make sure we are in proper schema */
2138         selectSourceSchema(fout, "pg_catalog");
2139
2140         /* Get the database owner and parameters from pg_database */
2141         if (fout->remoteVersion >= 80400)
2142         {
2143                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2144                                                   "(%s datdba) AS dba, "
2145                                                   "pg_encoding_to_char(encoding) AS encoding, "
2146                                                   "datcollate, datctype, datfrozenxid, "
2147                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2148                                           "shobj_description(oid, 'pg_database') AS description "
2149
2150                                                   "FROM pg_database "
2151                                                   "WHERE datname = ",
2152                                                   username_subquery);
2153                 appendStringLiteralAH(dbQry, datname, fout);
2154         }
2155         else if (fout->remoteVersion >= 80200)
2156         {
2157                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2158                                                   "(%s datdba) AS dba, "
2159                                                   "pg_encoding_to_char(encoding) AS encoding, "
2160                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2161                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2162                                           "shobj_description(oid, 'pg_database') AS description "
2163
2164                                                   "FROM pg_database "
2165                                                   "WHERE datname = ",
2166                                                   username_subquery);
2167                 appendStringLiteralAH(dbQry, datname, fout);
2168         }
2169         else if (fout->remoteVersion >= 80000)
2170         {
2171                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2172                                                   "(%s datdba) AS dba, "
2173                                                   "pg_encoding_to_char(encoding) AS encoding, "
2174                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2175                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2176                                                   "FROM pg_database "
2177                                                   "WHERE datname = ",
2178                                                   username_subquery);
2179                 appendStringLiteralAH(dbQry, datname, fout);
2180         }
2181         else if (fout->remoteVersion >= 70100)
2182         {
2183                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2184                                                   "(%s datdba) AS dba, "
2185                                                   "pg_encoding_to_char(encoding) AS encoding, "
2186                                                   "NULL AS datcollate, NULL AS datctype, "
2187                                                   "0 AS datfrozenxid, "
2188                                                   "NULL AS tablespace "
2189                                                   "FROM pg_database "
2190                                                   "WHERE datname = ",
2191                                                   username_subquery);
2192                 appendStringLiteralAH(dbQry, datname, fout);
2193         }
2194         else
2195         {
2196                 appendPQExpBuffer(dbQry, "SELECT "
2197                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2198                                                   "oid, "
2199                                                   "(%s datdba) AS dba, "
2200                                                   "pg_encoding_to_char(encoding) AS encoding, "
2201                                                   "NULL AS datcollate, NULL AS datctype, "
2202                                                   "0 AS datfrozenxid, "
2203                                                   "NULL AS tablespace "
2204                                                   "FROM pg_database "
2205                                                   "WHERE datname = ",
2206                                                   username_subquery);
2207                 appendStringLiteralAH(dbQry, datname, fout);
2208         }
2209
2210         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2211
2212         i_tableoid = PQfnumber(res, "tableoid");
2213         i_oid = PQfnumber(res, "oid");
2214         i_dba = PQfnumber(res, "dba");
2215         i_encoding = PQfnumber(res, "encoding");
2216         i_collate = PQfnumber(res, "datcollate");
2217         i_ctype = PQfnumber(res, "datctype");
2218         i_frozenxid = PQfnumber(res, "datfrozenxid");
2219         i_tablespace = PQfnumber(res, "tablespace");
2220
2221         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2222         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2223         dba = PQgetvalue(res, 0, i_dba);
2224         encoding = PQgetvalue(res, 0, i_encoding);
2225         collate = PQgetvalue(res, 0, i_collate);
2226         ctype = PQgetvalue(res, 0, i_ctype);
2227         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2228         tablespace = PQgetvalue(res, 0, i_tablespace);
2229
2230         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2231                                           fmtId(datname));
2232         if (strlen(encoding) > 0)
2233         {
2234                 appendPQExpBuffer(creaQry, " ENCODING = ");
2235                 appendStringLiteralAH(creaQry, encoding, fout);
2236         }
2237         if (strlen(collate) > 0)
2238         {
2239                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
2240                 appendStringLiteralAH(creaQry, collate, fout);
2241         }
2242         if (strlen(ctype) > 0)
2243         {
2244                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
2245                 appendStringLiteralAH(creaQry, ctype, fout);
2246         }
2247         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2248                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2249                                                   fmtId(tablespace));
2250         appendPQExpBuffer(creaQry, ";\n");
2251
2252         if (binary_upgrade)
2253         {
2254                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
2255                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2256                                                   "SET datfrozenxid = '%u'\n"
2257                                                   "WHERE        datname = ",
2258                                                   frozenxid);
2259                 appendStringLiteralAH(creaQry, datname, fout);
2260                 appendPQExpBuffer(creaQry, ";\n");
2261
2262         }
2263
2264         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2265                                           fmtId(datname));
2266
2267         dbDumpId = createDumpId();
2268
2269         ArchiveEntry(fout,
2270                                  dbCatId,               /* catalog ID */
2271                                  dbDumpId,              /* dump ID */
2272                                  datname,               /* Name */
2273                                  NULL,                  /* Namespace */
2274                                  NULL,                  /* Tablespace */
2275                                  dba,                   /* Owner */
2276                                  false,                 /* with oids */
2277                                  "DATABASE",    /* Desc */
2278                                  SECTION_PRE_DATA,              /* Section */
2279                                  creaQry->data, /* Create */
2280                                  delQry->data,  /* Del */
2281                                  NULL,                  /* Copy */
2282                                  NULL,                  /* Deps */
2283                                  0,                             /* # Deps */
2284                                  NULL,                  /* Dumper */
2285                                  NULL);                 /* Dumper Arg */
2286
2287         /*
2288          * pg_largeobject and pg_largeobject_metadata come from the old system
2289          * intact, so set their relfrozenxids.
2290          */
2291         if (binary_upgrade)
2292         {
2293                 PGresult   *lo_res;
2294                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2295                 PQExpBuffer loOutQry = createPQExpBuffer();
2296                 int                     i_relfrozenxid;
2297
2298                 /*
2299                  * pg_largeobject
2300                  */
2301                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2302                                                   "FROM pg_catalog.pg_class\n"
2303                                                   "WHERE oid = %u;\n",
2304                                                   LargeObjectRelationId);
2305
2306                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2307
2308                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2309
2310                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2311                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2312                                                   "SET relfrozenxid = '%u'\n"
2313                                                   "WHERE oid = %u;\n",
2314                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2315                                                   LargeObjectRelationId);
2316                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2317                                          "pg_largeobject", NULL, NULL, "",
2318                                          false, "pg_largeobject", SECTION_PRE_DATA,
2319                                          loOutQry->data, "", NULL,
2320                                          NULL, 0,
2321                                          NULL, NULL);
2322
2323                 PQclear(lo_res);
2324
2325                 /*
2326                  * pg_largeobject_metadata
2327                  */
2328                 if (fout->remoteVersion >= 90000)
2329                 {
2330                         resetPQExpBuffer(loFrozenQry);
2331                         resetPQExpBuffer(loOutQry);
2332
2333                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2334                                                           "FROM pg_catalog.pg_class\n"
2335                                                           "WHERE oid = %u;\n",
2336                                                           LargeObjectMetadataRelationId);
2337
2338                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2339
2340                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2341
2342                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2343                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2344                                                           "SET relfrozenxid = '%u'\n"
2345                                                           "WHERE oid = %u;\n",
2346                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2347                                                           LargeObjectMetadataRelationId);
2348                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2349                                                  "pg_largeobject_metadata", NULL, NULL, "",
2350                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2351                                                  loOutQry->data, "", NULL,
2352                                                  NULL, 0,
2353                                                  NULL, NULL);
2354
2355                         PQclear(lo_res);
2356                 }
2357
2358                 destroyPQExpBuffer(loFrozenQry);
2359                 destroyPQExpBuffer(loOutQry);
2360         }
2361
2362         /* Dump DB comment if any */
2363         if (fout->remoteVersion >= 80200)
2364         {
2365                 /*
2366                  * 8.2 keeps comments on shared objects in a shared table, so we
2367                  * cannot use the dumpComment used for other database objects.
2368                  */
2369                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2370
2371                 if (comment && strlen(comment))
2372                 {
2373                         resetPQExpBuffer(dbQry);
2374
2375                         /*
2376                          * Generates warning when loaded into a differently-named
2377                          * database.
2378                          */
2379                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2380                         appendStringLiteralAH(dbQry, comment, fout);
2381                         appendPQExpBuffer(dbQry, ";\n");
2382
2383                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2384                                                  dba, false, "COMMENT", SECTION_NONE,
2385                                                  dbQry->data, "", NULL,
2386                                                  &dbDumpId, 1, NULL, NULL);
2387                 }
2388         }
2389         else
2390         {
2391                 resetPQExpBuffer(dbQry);
2392                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2393                 dumpComment(fout, dbQry->data, NULL, "",
2394                                         dbCatId, 0, dbDumpId);
2395         }
2396
2397         PQclear(res);
2398
2399         /* Dump shared security label. */
2400         if (!no_security_labels && fout->remoteVersion >= 90200)
2401         {
2402                 PQExpBuffer seclabelQry = createPQExpBuffer();
2403
2404                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2405                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2406                 resetPQExpBuffer(seclabelQry);
2407                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2408                 if (strlen(seclabelQry->data))
2409                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2410                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2411                                                  seclabelQry->data, "", NULL,
2412                                                  &dbDumpId, 1, NULL, NULL);
2413                 destroyPQExpBuffer(seclabelQry);
2414         }
2415
2416         destroyPQExpBuffer(dbQry);
2417         destroyPQExpBuffer(delQry);
2418         destroyPQExpBuffer(creaQry);
2419 }
2420
2421
2422 /*
2423  * dumpEncoding: put the correct encoding into the archive
2424  */
2425 static void
2426 dumpEncoding(Archive *AH)
2427 {
2428         const char *encname = pg_encoding_to_char(AH->encoding);
2429         PQExpBuffer qry = createPQExpBuffer();
2430
2431         if (g_verbose)
2432                 write_msg(NULL, "saving encoding = %s\n", encname);
2433
2434         appendPQExpBuffer(qry, "SET client_encoding = ");
2435         appendStringLiteralAH(qry, encname, AH);
2436         appendPQExpBuffer(qry, ";\n");
2437
2438         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2439                                  "ENCODING", NULL, NULL, "",
2440                                  false, "ENCODING", SECTION_PRE_DATA,
2441                                  qry->data, "", NULL,
2442                                  NULL, 0,
2443                                  NULL, NULL);
2444
2445         destroyPQExpBuffer(qry);
2446 }
2447
2448
2449 /*
2450  * dumpStdStrings: put the correct escape string behavior into the archive
2451  */
2452 static void
2453 dumpStdStrings(Archive *AH)
2454 {
2455         const char *stdstrings = AH->std_strings ? "on" : "off";
2456         PQExpBuffer qry = createPQExpBuffer();
2457
2458         if (g_verbose)
2459                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2460                                   stdstrings);
2461
2462         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2463                                           stdstrings);
2464
2465         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2466                                  "STDSTRINGS", NULL, NULL, "",
2467                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2468                                  qry->data, "", NULL,
2469                                  NULL, 0,
2470                                  NULL, NULL);
2471
2472         destroyPQExpBuffer(qry);
2473 }
2474
2475
2476 /*
2477  * getBlobs:
2478  *      Collect schema-level data about large objects
2479  */
2480 static void
2481 getBlobs(Archive *fout)
2482 {
2483         PQExpBuffer blobQry = createPQExpBuffer();
2484         BlobInfo   *binfo;
2485         DumpableObject *bdata;
2486         PGresult   *res;
2487         int                     ntups;
2488         int                     i;
2489
2490         /* Verbose message */
2491         if (g_verbose)
2492                 write_msg(NULL, "reading large objects\n");
2493
2494         /* Make sure we are in proper schema */
2495         selectSourceSchema(fout, "pg_catalog");
2496
2497         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2498         if (fout->remoteVersion >= 90000)
2499                 appendPQExpBuffer(blobQry,
2500                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2501                                                   " FROM pg_largeobject_metadata",
2502                                                   username_subquery);
2503         else if (fout->remoteVersion >= 70100)
2504                 appendPQExpBuffer(blobQry,
2505                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2506                                                   " FROM pg_largeobject");
2507         else
2508                 appendPQExpBuffer(blobQry,
2509                                                   "SELECT oid, NULL::oid, NULL::oid"
2510                                                   " FROM pg_class WHERE relkind = 'l'");
2511
2512         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2513
2514         ntups = PQntuples(res);
2515         if (ntups > 0)
2516         {
2517                 /*
2518                  * Each large object has its own BLOB archive entry.
2519                  */
2520                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2521
2522                 for (i = 0; i < ntups; i++)
2523                 {
2524                         binfo[i].dobj.objType = DO_BLOB;
2525                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2526                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2527                         AssignDumpId(&binfo[i].dobj);
2528
2529                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2530                         if (!PQgetisnull(res, i, 1))
2531                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2532                         else
2533                                 binfo[i].rolname = "";
2534                         if (!PQgetisnull(res, i, 2))
2535                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2536                         else
2537                                 binfo[i].blobacl = NULL;
2538                 }
2539
2540                 /*
2541                  * If we have any large objects, a "BLOBS" archive entry is needed.
2542                  * This is just a placeholder for sorting; it carries no data now.
2543                  */
2544                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2545                 bdata->objType = DO_BLOB_DATA;
2546                 bdata->catId = nilCatalogId;
2547                 AssignDumpId(bdata);
2548                 bdata->name = pg_strdup("BLOBS");
2549         }
2550
2551         PQclear(res);
2552         destroyPQExpBuffer(blobQry);
2553 }
2554
2555 /*
2556  * dumpBlob
2557  *
2558  * dump the definition (metadata) of the given large object
2559  */
2560 static void
2561 dumpBlob(Archive *fout, BlobInfo *binfo)
2562 {
2563         PQExpBuffer cquery = createPQExpBuffer();
2564         PQExpBuffer dquery = createPQExpBuffer();
2565
2566         appendPQExpBuffer(cquery,
2567                                           "SELECT pg_catalog.lo_create('%s');\n",
2568                                           binfo->dobj.name);
2569
2570         appendPQExpBuffer(dquery,
2571                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2572                                           binfo->dobj.name);
2573
2574         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2575                                  binfo->dobj.name,
2576                                  NULL, NULL,
2577                                  binfo->rolname, false,
2578                                  "BLOB", SECTION_PRE_DATA,
2579                                  cquery->data, dquery->data, NULL,
2580                                  NULL, 0,
2581                                  NULL, NULL);
2582
2583         /* set up tag for comment and/or ACL */
2584         resetPQExpBuffer(cquery);
2585         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2586
2587         /* Dump comment if any */
2588         dumpComment(fout, cquery->data,
2589                                 NULL, binfo->rolname,
2590                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2591
2592         /* Dump security label if any */
2593         dumpSecLabel(fout, cquery->data,
2594                                  NULL, binfo->rolname,
2595                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2596
2597         /* Dump ACL if any */
2598         if (binfo->blobacl)
2599                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2600                                 binfo->dobj.name, NULL, cquery->data,
2601                                 NULL, binfo->rolname, binfo->blobacl);
2602
2603         destroyPQExpBuffer(cquery);
2604         destroyPQExpBuffer(dquery);
2605 }
2606
2607 /*
2608  * dumpBlobs:
2609  *      dump the data contents of all large objects
2610  */
2611 static int
2612 dumpBlobs(Archive *fout, void *arg)
2613 {
2614         const char *blobQry;
2615         const char *blobFetchQry;
2616         PGconn     *conn = GetConnection(fout);
2617         PGresult   *res;
2618         char            buf[LOBBUFSIZE];
2619         int                     ntups;
2620         int                     i;
2621         int                     cnt;
2622
2623         if (g_verbose)
2624                 write_msg(NULL, "saving large objects\n");
2625
2626         /* Make sure we are in proper schema */
2627         selectSourceSchema(fout, "pg_catalog");
2628
2629         /*
2630          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2631          * the already-in-memory dumpable objects instead...
2632          */
2633         if (fout->remoteVersion >= 90000)
2634                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2635         else if (fout->remoteVersion >= 70100)
2636                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2637         else
2638                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2639
2640         ExecuteSqlStatement(fout, blobQry);
2641
2642         /* Command to fetch from cursor */
2643         blobFetchQry = "FETCH 1000 IN bloboid";
2644
2645         do
2646         {
2647                 /* Do a fetch */
2648                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2649
2650                 /* Process the tuples, if any */
2651                 ntups = PQntuples(res);
2652                 for (i = 0; i < ntups; i++)
2653                 {
2654                         Oid                     blobOid;
2655                         int                     loFd;
2656
2657                         blobOid = atooid(PQgetvalue(res, i, 0));
2658                         /* Open the BLOB */
2659                         loFd = lo_open(conn, blobOid, INV_READ);
2660                         if (loFd == -1)
2661                                 exit_horribly(NULL, "could not open large object %u: %s",
2662                                                           blobOid, PQerrorMessage(conn));
2663
2664                         StartBlob(fout, blobOid);
2665
2666                         /* Now read it in chunks, sending data to archive */
2667                         do
2668                         {
2669                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2670                                 if (cnt < 0)
2671                                         exit_horribly(NULL, "error reading large object %u: %s",
2672                                                                   blobOid, PQerrorMessage(conn));
2673
2674                                 WriteData(fout, buf, cnt);
2675                         } while (cnt > 0);
2676
2677                         lo_close(conn, loFd);
2678
2679                         EndBlob(fout, blobOid);
2680                 }
2681
2682                 PQclear(res);
2683         } while (ntups > 0);
2684
2685         return 1;
2686 }
2687
2688 static void
2689 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2690                                                                                  PQExpBuffer upgrade_buffer,
2691                                                                                  Oid pg_type_oid)
2692 {
2693         PQExpBuffer upgrade_query = createPQExpBuffer();
2694         PGresult   *upgrade_res;
2695         Oid                     pg_type_array_oid;
2696
2697         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2698         appendPQExpBuffer(upgrade_buffer,
2699          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2700                                           pg_type_oid);
2701
2702         /* we only support old >= 8.3 for binary upgrades */
2703         appendPQExpBuffer(upgrade_query,
2704                                           "SELECT typarray "
2705                                           "FROM pg_catalog.pg_type "
2706                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2707                                           pg_type_oid);
2708
2709         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2710
2711         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2712
2713         if (OidIsValid(pg_type_array_oid))
2714         {
2715                 appendPQExpBuffer(upgrade_buffer,
2716                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2717                 appendPQExpBuffer(upgrade_buffer,
2718                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2719                                                   pg_type_array_oid);
2720         }
2721
2722         PQclear(upgrade_res);
2723         destroyPQExpBuffer(upgrade_query);
2724 }
2725
2726 static bool
2727 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2728                                                                                 PQExpBuffer upgrade_buffer,
2729                                                                                 Oid pg_rel_oid)
2730 {
2731         PQExpBuffer upgrade_query = createPQExpBuffer();
2732         PGresult   *upgrade_res;
2733         Oid                     pg_type_oid;
2734         bool            toast_set = false;
2735
2736         /* we only support old >= 8.3 for binary upgrades */
2737         appendPQExpBuffer(upgrade_query,
2738                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2739                                           "FROM pg_catalog.pg_class c "
2740                                           "LEFT JOIN pg_catalog.pg_class t ON "
2741                                           "  (c.reltoastrelid = t.oid) "
2742                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2743                                           pg_rel_oid);
2744
2745         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2746
2747         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2748
2749         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2750                                                                                          pg_type_oid);
2751
2752         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2753         {
2754                 /* Toast tables do not have pg_type array rows */
2755                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2756                                                                                         PQfnumber(upgrade_res, "trel")));
2757
2758                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2759                 appendPQExpBuffer(upgrade_buffer,
2760                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2761                                                   pg_type_toast_oid);
2762
2763                 toast_set = true;
2764         }
2765
2766         PQclear(upgrade_res);
2767         destroyPQExpBuffer(upgrade_query);
2768
2769         return toast_set;
2770 }
2771
2772 static void
2773 binary_upgrade_set_pg_class_oids(Archive *fout,
2774                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2775                                                                  bool is_index)
2776 {
2777         PQExpBuffer upgrade_query = createPQExpBuffer();
2778         PGresult   *upgrade_res;
2779         Oid                     pg_class_reltoastrelid;
2780         Oid                     pg_class_reltoastidxid;
2781
2782         appendPQExpBuffer(upgrade_query,
2783                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2784                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2785                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2786                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2787                                           pg_class_oid);
2788
2789         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2790
2791         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2792         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2793
2794         appendPQExpBuffer(upgrade_buffer,
2795                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2796
2797         if (!is_index)
2798         {
2799                 appendPQExpBuffer(upgrade_buffer,
2800                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2801                                                   pg_class_oid);
2802                 /* only tables have toast tables, not indexes */
2803                 if (OidIsValid(pg_class_reltoastrelid))
2804                 {
2805                         /*
2806                          * One complexity is that the table definition might not require
2807                          * the creation of a TOAST table, and the TOAST table might have
2808                          * been created long after table creation, when the table was
2809                          * loaded with wide data.  By setting the TOAST oid we force
2810                          * creation of the TOAST heap and TOAST index by the backend so we
2811                          * can cleanly copy the files during binary upgrade.
2812                          */
2813
2814                         appendPQExpBuffer(upgrade_buffer,
2815                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2816                                                           pg_class_reltoastrelid);
2817
2818                         /* every toast table has an index */
2819                         appendPQExpBuffer(upgrade_buffer,
2820                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2821                                                           pg_class_reltoastidxid);
2822                 }
2823         }
2824         else
2825                 appendPQExpBuffer(upgrade_buffer,
2826                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2827                                                   pg_class_oid);
2828
2829         appendPQExpBuffer(upgrade_buffer, "\n");
2830
2831         PQclear(upgrade_res);
2832         destroyPQExpBuffer(upgrade_query);
2833 }
2834
2835 /*
2836  * If the DumpableObject is a member of an extension, add a suitable
2837  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2838  */
2839 static void
2840 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2841                                                                 DumpableObject *dobj,
2842                                                                 const char *objlabel)
2843 {
2844         DumpableObject *extobj = NULL;
2845         int                     i;
2846
2847         if (!dobj->ext_member)
2848                 return;
2849
2850         /*
2851          * Find the parent extension.  We could avoid this search if we wanted to
2852          * add a link field to DumpableObject, but the space costs of that would
2853          * be considerable.  We assume that member objects could only have a
2854          * direct dependency on their own extension, not any others.
2855          */
2856         for (i = 0; i < dobj->nDeps; i++)
2857         {
2858                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2859                 if (extobj && extobj->objType == DO_EXTENSION)
2860                         break;
2861                 extobj = NULL;
2862         }
2863         if (extobj == NULL)
2864                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2865
2866         appendPQExpBuffer(upgrade_buffer,
2867           "\n-- For binary upgrade, handle extension membership the hard way\n");
2868         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2869                                           fmtId(extobj->name),
2870                                           objlabel);
2871 }
2872
2873 /*
2874  * getNamespaces:
2875  *        read all namespaces in the system catalogs and return them in the
2876  * NamespaceInfo* structure
2877  *
2878  *      numNamespaces is set to the number of namespaces read in
2879  */
2880 NamespaceInfo *
2881 getNamespaces(Archive *fout, int *numNamespaces)
2882 {
2883         PGresult   *res;
2884         int                     ntups;
2885         int                     i;
2886         PQExpBuffer query;
2887         NamespaceInfo *nsinfo;
2888         int                     i_tableoid;
2889         int                     i_oid;
2890         int                     i_nspname;
2891         int                     i_rolname;
2892         int                     i_nspacl;
2893
2894         /*
2895          * Before 7.3, there are no real namespaces; create two dummy entries, one
2896          * for user stuff and one for system stuff.
2897          */
2898         if (fout->remoteVersion < 70300)
2899         {
2900                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2901
2902                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2903                 nsinfo[0].dobj.catId.tableoid = 0;
2904                 nsinfo[0].dobj.catId.oid = 0;
2905                 AssignDumpId(&nsinfo[0].dobj);
2906                 nsinfo[0].dobj.name = pg_strdup("public");
2907                 nsinfo[0].rolname = pg_strdup("");
2908                 nsinfo[0].nspacl = pg_strdup("");
2909
2910                 selectDumpableNamespace(&nsinfo[0]);
2911
2912                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2913                 nsinfo[1].dobj.catId.tableoid = 0;
2914                 nsinfo[1].dobj.catId.oid = 1;
2915                 AssignDumpId(&nsinfo[1].dobj);
2916                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2917                 nsinfo[1].rolname = pg_strdup("");
2918                 nsinfo[1].nspacl = pg_strdup("");
2919
2920                 selectDumpableNamespace(&nsinfo[1]);
2921
2922                 *numNamespaces = 2;
2923
2924                 return nsinfo;
2925         }
2926
2927         query = createPQExpBuffer();
2928
2929         /* Make sure we are in proper schema */
2930         selectSourceSchema(fout, "pg_catalog");
2931
2932         /*
2933          * we fetch all namespaces including system ones, so that every object we
2934          * read in can be linked to a containing namespace.
2935          */
2936         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2937                                           "(%s nspowner) AS rolname, "
2938                                           "nspacl FROM pg_namespace",
2939                                           username_subquery);
2940
2941         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2942
2943         ntups = PQntuples(res);
2944
2945         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2946
2947         i_tableoid = PQfnumber(res, "tableoid");
2948         i_oid = PQfnumber(res, "oid");
2949         i_nspname = PQfnumber(res, "nspname");
2950         i_rolname = PQfnumber(res, "rolname");
2951         i_nspacl = PQfnumber(res, "nspacl");
2952
2953         for (i = 0; i < ntups; i++)
2954         {
2955                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2956                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2957                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2958                 AssignDumpId(&nsinfo[i].dobj);
2959                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2960                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2961                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2962
2963                 /* Decide whether to dump this namespace */
2964                 selectDumpableNamespace(&nsinfo[i]);
2965
2966                 if (strlen(nsinfo[i].rolname) == 0)
2967                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2968                                           nsinfo[i].dobj.name);
2969         }
2970
2971         PQclear(res);
2972         destroyPQExpBuffer(query);
2973
2974         *numNamespaces = ntups;
2975
2976         return nsinfo;
2977 }
2978
2979 /*
2980  * findNamespace:
2981  *              given a namespace OID and an object OID, look up the info read by
2982  *              getNamespaces
2983  *
2984  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2985  * a system object or not.      In 7.3 and later there is no guessing, and we
2986  * don't use objoid at all.
2987  */
2988 static NamespaceInfo *
2989 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
2990 {
2991         NamespaceInfo *nsinfo;
2992
2993         if (fout->remoteVersion >= 70300)
2994         {
2995                 nsinfo = findNamespaceByOid(nsoid);
2996         }
2997         else
2998         {
2999                 /* This code depends on the dummy objects set up by getNamespaces. */
3000                 Oid                     i;
3001
3002                 if (objoid > g_last_builtin_oid)
3003                         i = 0;                          /* user object */
3004                 else
3005                         i = 1;                          /* system object */
3006                 nsinfo = findNamespaceByOid(i);
3007         }
3008
3009         if (nsinfo == NULL)
3010                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3011
3012         return nsinfo;
3013 }
3014
3015 /*
3016  * getExtensions:
3017  *        read all extensions in the system catalogs and return them in the
3018  * ExtensionInfo* structure
3019  *
3020  *      numExtensions is set to the number of extensions read in
3021  */
3022 ExtensionInfo *
3023 getExtensions(Archive *fout, int *numExtensions)
3024 {
3025         PGresult   *res;
3026         int                     ntups;
3027         int                     i;
3028         PQExpBuffer query;
3029         ExtensionInfo *extinfo;
3030         int                     i_tableoid;
3031         int                     i_oid;
3032         int                     i_extname;
3033         int                     i_nspname;
3034         int                     i_extrelocatable;
3035         int                     i_extversion;
3036         int                     i_extconfig;
3037         int                     i_extcondition;
3038
3039         /*
3040          * Before 9.1, there are no extensions.
3041          */
3042         if (fout->remoteVersion < 90100)
3043         {
3044                 *numExtensions = 0;
3045                 return NULL;
3046         }
3047
3048         query = createPQExpBuffer();
3049
3050         /* Make sure we are in proper schema */
3051         selectSourceSchema(fout, "pg_catalog");
3052
3053         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
3054                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3055                                           "FROM pg_extension x "
3056                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
3057
3058         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3059
3060         ntups = PQntuples(res);
3061
3062         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3063
3064         i_tableoid = PQfnumber(res, "tableoid");
3065         i_oid = PQfnumber(res, "oid");
3066         i_extname = PQfnumber(res, "extname");
3067         i_nspname = PQfnumber(res, "nspname");
3068         i_extrelocatable = PQfnumber(res, "extrelocatable");
3069         i_extversion = PQfnumber(res, "extversion");
3070         i_extconfig = PQfnumber(res, "extconfig");
3071         i_extcondition = PQfnumber(res, "extcondition");
3072
3073         for (i = 0; i < ntups; i++)
3074         {
3075                 extinfo[i].dobj.objType = DO_EXTENSION;
3076                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3077                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3078                 AssignDumpId(&extinfo[i].dobj);
3079                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3080                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3081                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3082                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3083                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3084                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3085
3086                 /* Decide whether we want to dump it */
3087                 selectDumpableExtension(&(extinfo[i]));
3088         }
3089
3090         PQclear(res);
3091         destroyPQExpBuffer(query);
3092
3093         *numExtensions = ntups;
3094
3095         return extinfo;
3096 }
3097
3098 /*
3099  * getTypes:
3100  *        read all types in the system catalogs and return them in the
3101  * TypeInfo* structure
3102  *
3103  *      numTypes is set to the number of types read in
3104  *
3105  * NB: this must run after getFuncs() because we assume we can do
3106  * findFuncByOid().
3107  */
3108 TypeInfo *
3109 getTypes(Archive *fout, int *numTypes)
3110 {
3111         PGresult   *res;
3112         int                     ntups;
3113         int                     i;
3114         PQExpBuffer query = createPQExpBuffer();
3115         TypeInfo   *tyinfo;
3116         ShellTypeInfo *stinfo;
3117         int                     i_tableoid;
3118         int                     i_oid;
3119         int                     i_typname;
3120         int                     i_typnamespace;
3121         int                     i_typacl;
3122         int                     i_rolname;
3123         int                     i_typinput;
3124         int                     i_typoutput;
3125         int                     i_typelem;
3126         int                     i_typrelid;
3127         int                     i_typrelkind;
3128         int                     i_typtype;
3129         int                     i_typisdefined;
3130         int                     i_isarray;
3131
3132         /*
3133          * we include even the built-in types because those may be used as array
3134          * elements by user-defined types
3135          *
3136          * we filter out the built-in types when we dump out the types
3137          *
3138          * same approach for undefined (shell) types and array types
3139          *
3140          * Note: as of 8.3 we can reliably detect whether a type is an
3141          * auto-generated array type by checking the element type's typarray.
3142          * (Before that the test is capable of generating false positives.) We
3143          * still check for name beginning with '_', though, so as to avoid the
3144          * cost of the subselect probe for all standard types.  This would have to
3145          * be revisited if the backend ever allows renaming of array types.
3146          */
3147
3148         /* Make sure we are in proper schema */
3149         selectSourceSchema(fout, "pg_catalog");
3150
3151         if (fout->remoteVersion >= 90200)
3152         {
3153                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3154                                                   "typnamespace, typacl, "
3155                                                   "(%s typowner) AS rolname, "
3156                                                   "typinput::oid AS typinput, "
3157                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3158                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3159                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3160                                                   "typtype, typisdefined, "
3161                                                   "typname[0] = '_' AND typelem != 0 AND "
3162                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3163                                                   "FROM pg_type",
3164                                                   username_subquery);
3165         }
3166         else if (fout->remoteVersion >= 80300)
3167         {
3168                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3169                                                   "typnamespace, '{=U}' AS typacl, "
3170                                                   "(%s typowner) AS rolname, "
3171                                                   "typinput::oid AS typinput, "
3172                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3173                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3174                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3175                                                   "typtype, typisdefined, "
3176                                                   "typname[0] = '_' AND typelem != 0 AND "
3177                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3178                                                   "FROM pg_type",
3179                                                   username_subquery);
3180         }
3181         else if (fout->remoteVersion >= 70300)
3182         {
3183                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3184                                                   "typnamespace, '{=U}' AS typacl, "
3185                                                   "(%s typowner) AS rolname, "
3186                                                   "typinput::oid AS typinput, "
3187                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3188                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3189                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3190                                                   "typtype, typisdefined, "
3191                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3192                                                   "FROM pg_type",
3193                                                   username_subquery);
3194         }
3195         else if (fout->remoteVersion >= 70100)
3196         {
3197                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3198                                                   "0::oid AS 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 AS isarray "
3206                                                   "FROM pg_type",
3207                                                   username_subquery);
3208         }
3209         else
3210         {
3211                 appendPQExpBuffer(query, "SELECT "
3212                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3213                                                   "oid, typname, "
3214                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3215                                                   "(%s typowner) AS rolname, "
3216                                                   "typinput::oid AS typinput, "
3217                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3218                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3219                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3220                                                   "typtype, typisdefined, "
3221                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3222                                                   "FROM pg_type",
3223                                                   username_subquery);
3224         }
3225
3226         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3227
3228         ntups = PQntuples(res);
3229
3230         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3231
3232         i_tableoid = PQfnumber(res, "tableoid");
3233         i_oid = PQfnumber(res, "oid");
3234         i_typname = PQfnumber(res, "typname");
3235         i_typnamespace = PQfnumber(res, "typnamespace");
3236         i_typacl = PQfnumber(res, "typacl");
3237         i_rolname = PQfnumber(res, "rolname");
3238         i_typinput = PQfnumber(res, "typinput");
3239         i_typoutput = PQfnumber(res, "typoutput");
3240         i_typelem = PQfnumber(res, "typelem");
3241         i_typrelid = PQfnumber(res, "typrelid");
3242         i_typrelkind = PQfnumber(res, "typrelkind");
3243         i_typtype = PQfnumber(res, "typtype");
3244         i_typisdefined = PQfnumber(res, "typisdefined");
3245         i_isarray = PQfnumber(res, "isarray");
3246
3247         for (i = 0; i < ntups; i++)
3248         {
3249                 tyinfo[i].dobj.objType = DO_TYPE;
3250                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3251                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3252                 AssignDumpId(&tyinfo[i].dobj);
3253                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3254                 tyinfo[i].dobj.namespace =
3255                         findNamespace(fout,
3256                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3257                                                   tyinfo[i].dobj.catId.oid);
3258                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3259                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3260                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3261                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3262                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3263                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3264                 tyinfo[i].shellType = NULL;
3265
3266                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3267                         tyinfo[i].isDefined = true;
3268                 else
3269                         tyinfo[i].isDefined = false;
3270
3271                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3272                         tyinfo[i].isArray = true;
3273                 else
3274                         tyinfo[i].isArray = false;
3275
3276                 /* Decide whether we want to dump it */
3277                 selectDumpableType(&tyinfo[i]);
3278
3279                 /*
3280                  * If it's a domain, fetch info about its constraints, if any
3281                  */
3282                 tyinfo[i].nDomChecks = 0;
3283                 tyinfo[i].domChecks = NULL;
3284                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3285                         getDomainConstraints(fout, &(tyinfo[i]));
3286
3287                 /*
3288                  * If it's a base type, make a DumpableObject representing a shell
3289                  * definition of the type.      We will need to dump that ahead of the I/O
3290                  * functions for the type.      Similarly, range types need a shell
3291                  * definition in case they have a canonicalize function.
3292                  *
3293                  * Note: the shell type doesn't have a catId.  You might think it
3294                  * should copy the base type's catId, but then it might capture the
3295                  * pg_depend entries for the type, which we don't want.
3296                  */
3297                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3298                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3299                 {
3300                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3301                         stinfo->dobj.objType = DO_SHELL_TYPE;
3302                         stinfo->dobj.catId = nilCatalogId;
3303                         AssignDumpId(&stinfo->dobj);
3304                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3305                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3306                         stinfo->baseType = &(tyinfo[i]);
3307                         tyinfo[i].shellType = stinfo;
3308
3309                         /*
3310                          * Initially mark the shell type as not to be dumped.  We'll only
3311                          * dump it if the I/O or canonicalize functions need to be dumped;
3312                          * this is taken care of while sorting dependencies.
3313                          */
3314                         stinfo->dobj.dump = false;
3315
3316                         /*
3317                          * However, if dumping from pre-7.3, there will be no dependency
3318                          * info so we have to fake it here.  We only need to worry about
3319                          * typinput and typoutput since the other functions only exist
3320                          * post-7.3.
3321                          */
3322                         if (fout->remoteVersion < 70300)
3323                         {
3324                                 Oid                     typinput;
3325                                 Oid                     typoutput;
3326                                 FuncInfo   *funcInfo;
3327
3328                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3329                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3330
3331                                 funcInfo = findFuncByOid(typinput);
3332                                 if (funcInfo && funcInfo->dobj.dump)
3333                                 {
3334                                         /* base type depends on function */
3335                                         addObjectDependency(&tyinfo[i].dobj,
3336                                                                                 funcInfo->dobj.dumpId);
3337                                         /* function depends on shell type */
3338                                         addObjectDependency(&funcInfo->dobj,
3339                                                                                 stinfo->dobj.dumpId);
3340                                         /* mark shell type as to be dumped */
3341                                         stinfo->dobj.dump = true;
3342                                 }
3343
3344                                 funcInfo = findFuncByOid(typoutput);
3345                                 if (funcInfo && funcInfo->dobj.dump)
3346                                 {
3347                                         /* base type depends on function */
3348                                         addObjectDependency(&tyinfo[i].dobj,
3349                                                                                 funcInfo->dobj.dumpId);
3350                                         /* function depends on shell type */
3351                                         addObjectDependency(&funcInfo->dobj,
3352                                                                                 stinfo->dobj.dumpId);
3353                                         /* mark shell type as to be dumped */
3354                                         stinfo->dobj.dump = true;
3355                                 }
3356                         }
3357                 }
3358
3359                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3360                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3361                                           tyinfo[i].dobj.name);
3362         }
3363
3364         *numTypes = ntups;
3365
3366         PQclear(res);
3367
3368         destroyPQExpBuffer(query);
3369
3370         return tyinfo;
3371 }
3372
3373 /*
3374  * getOperators:
3375  *        read all operators in the system catalogs and return them in the
3376  * OprInfo* structure
3377  *
3378  *      numOprs is set to the number of operators read in
3379  */
3380 OprInfo *
3381 getOperators(Archive *fout, int *numOprs)
3382 {
3383         PGresult   *res;
3384         int                     ntups;
3385         int                     i;
3386         PQExpBuffer query = createPQExpBuffer();
3387         OprInfo    *oprinfo;
3388         int                     i_tableoid;
3389         int                     i_oid;
3390         int                     i_oprname;
3391         int                     i_oprnamespace;
3392         int                     i_rolname;
3393         int                     i_oprkind;
3394         int                     i_oprcode;
3395
3396         /*
3397          * find all operators, including builtin operators; we filter out
3398          * system-defined operators at dump-out time.
3399          */
3400
3401         /* Make sure we are in proper schema */
3402         selectSourceSchema(fout, "pg_catalog");
3403
3404         if (fout->remoteVersion >= 70300)
3405         {
3406                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3407                                                   "oprnamespace, "
3408                                                   "(%s oprowner) AS rolname, "
3409                                                   "oprkind, "
3410                                                   "oprcode::oid AS oprcode "
3411                                                   "FROM pg_operator",
3412                                                   username_subquery);
3413         }
3414         else if (fout->remoteVersion >= 70100)
3415         {
3416                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3417                                                   "0::oid AS oprnamespace, "
3418                                                   "(%s oprowner) AS rolname, "
3419                                                   "oprkind, "
3420                                                   "oprcode::oid AS oprcode "
3421                                                   "FROM pg_operator",
3422                                                   username_subquery);
3423         }
3424         else
3425         {
3426                 appendPQExpBuffer(query, "SELECT "
3427                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3428                                                   "oid, oprname, "
3429                                                   "0::oid AS oprnamespace, "
3430                                                   "(%s oprowner) AS rolname, "
3431                                                   "oprkind, "
3432                                                   "oprcode::oid AS oprcode "
3433                                                   "FROM pg_operator",
3434                                                   username_subquery);
3435         }
3436
3437         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3438
3439         ntups = PQntuples(res);
3440         *numOprs = ntups;
3441
3442         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3443
3444         i_tableoid = PQfnumber(res, "tableoid");
3445         i_oid = PQfnumber(res, "oid");
3446         i_oprname = PQfnumber(res, "oprname");
3447         i_oprnamespace = PQfnumber(res, "oprnamespace");
3448         i_rolname = PQfnumber(res, "rolname");
3449         i_oprkind = PQfnumber(res, "oprkind");
3450         i_oprcode = PQfnumber(res, "oprcode");
3451
3452         for (i = 0; i < ntups; i++)
3453         {
3454                 oprinfo[i].dobj.objType = DO_OPERATOR;
3455                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3456                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3457                 AssignDumpId(&oprinfo[i].dobj);
3458                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3459                 oprinfo[i].dobj.namespace =
3460                         findNamespace(fout,
3461                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3462                                                   oprinfo[i].dobj.catId.oid);
3463                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3464                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3465                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3466
3467                 /* Decide whether we want to dump it */
3468                 selectDumpableObject(&(oprinfo[i].dobj));
3469
3470                 if (strlen(oprinfo[i].rolname) == 0)
3471                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3472                                           oprinfo[i].dobj.name);
3473         }
3474
3475         PQclear(res);
3476
3477         destroyPQExpBuffer(query);
3478
3479         return oprinfo;
3480 }
3481
3482 /*
3483  * getCollations:
3484  *        read all collations in the system catalogs and return them in the
3485  * CollInfo* structure
3486  *
3487  *      numCollations is set to the number of collations read in
3488  */
3489 CollInfo *
3490 getCollations(Archive *fout, int *numCollations)
3491 {
3492         PGresult   *res;
3493         int                     ntups;
3494         int                     i;
3495         PQExpBuffer query;
3496         CollInfo   *collinfo;
3497         int                     i_tableoid;
3498         int                     i_oid;
3499         int                     i_collname;
3500         int                     i_collnamespace;
3501         int                     i_rolname;
3502
3503         /* Collations didn't exist pre-9.1 */
3504         if (fout->remoteVersion < 90100)
3505         {
3506                 *numCollations = 0;
3507                 return NULL;
3508         }
3509
3510         query = createPQExpBuffer();
3511
3512         /*
3513          * find all collations, including builtin collations; we filter out
3514          * system-defined collations at dump-out time.
3515          */
3516
3517         /* Make sure we are in proper schema */
3518         selectSourceSchema(fout, "pg_catalog");
3519
3520         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3521                                           "collnamespace, "
3522                                           "(%s collowner) AS rolname "
3523                                           "FROM pg_collation",
3524                                           username_subquery);
3525
3526         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3527
3528         ntups = PQntuples(res);
3529         *numCollations = ntups;
3530
3531         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3532
3533         i_tableoid = PQfnumber(res, "tableoid");
3534         i_oid = PQfnumber(res, "oid");
3535         i_collname = PQfnumber(res, "collname");
3536         i_collnamespace = PQfnumber(res, "collnamespace");
3537         i_rolname = PQfnumber(res, "rolname");
3538
3539         for (i = 0; i < ntups; i++)
3540         {
3541                 collinfo[i].dobj.objType = DO_COLLATION;
3542                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3543                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3544                 AssignDumpId(&collinfo[i].dobj);
3545                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3546                 collinfo[i].dobj.namespace =
3547                         findNamespace(fout,
3548                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3549                                                   collinfo[i].dobj.catId.oid);
3550                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3551
3552                 /* Decide whether we want to dump it */
3553                 selectDumpableObject(&(collinfo[i].dobj));
3554         }
3555
3556         PQclear(res);
3557
3558         destroyPQExpBuffer(query);
3559
3560         return collinfo;
3561 }
3562
3563 /*
3564  * getConversions:
3565  *        read all conversions in the system catalogs and return them in the
3566  * ConvInfo* structure
3567  *
3568  *      numConversions is set to the number of conversions read in
3569  */
3570 ConvInfo *
3571 getConversions(Archive *fout, int *numConversions)
3572 {
3573         PGresult   *res;
3574         int                     ntups;
3575         int                     i;
3576         PQExpBuffer query = createPQExpBuffer();
3577         ConvInfo   *convinfo;
3578         int                     i_tableoid;
3579         int                     i_oid;
3580         int                     i_conname;
3581         int                     i_connamespace;
3582         int                     i_rolname;
3583
3584         /* Conversions didn't exist pre-7.3 */
3585         if (fout->remoteVersion < 70300)
3586         {
3587                 *numConversions = 0;
3588                 return NULL;
3589         }
3590
3591         /*
3592          * find all conversions, including builtin conversions; we filter out
3593          * system-defined conversions at dump-out time.
3594          */
3595
3596         /* Make sure we are in proper schema */
3597         selectSourceSchema(fout, "pg_catalog");
3598
3599         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3600                                           "connamespace, "
3601                                           "(%s conowner) AS rolname "
3602                                           "FROM pg_conversion",
3603                                           username_subquery);
3604
3605         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3606
3607         ntups = PQntuples(res);
3608         *numConversions = ntups;
3609
3610         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3611
3612         i_tableoid = PQfnumber(res, "tableoid");
3613         i_oid = PQfnumber(res, "oid");
3614         i_conname = PQfnumber(res, "conname");
3615         i_connamespace = PQfnumber(res, "connamespace");
3616         i_rolname = PQfnumber(res, "rolname");
3617
3618         for (i = 0; i < ntups; i++)
3619         {
3620                 convinfo[i].dobj.objType = DO_CONVERSION;
3621                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3622                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3623                 AssignDumpId(&convinfo[i].dobj);
3624                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3625                 convinfo[i].dobj.namespace =
3626                         findNamespace(fout,
3627                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3628                                                   convinfo[i].dobj.catId.oid);
3629                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3630
3631                 /* Decide whether we want to dump it */
3632                 selectDumpableObject(&(convinfo[i].dobj));
3633         }
3634
3635         PQclear(res);
3636
3637         destroyPQExpBuffer(query);
3638
3639         return convinfo;
3640 }
3641
3642 /*
3643  * getOpclasses:
3644  *        read all opclasses in the system catalogs and return them in the
3645  * OpclassInfo* structure
3646  *
3647  *      numOpclasses is set to the number of opclasses read in
3648  */
3649 OpclassInfo *
3650 getOpclasses(Archive *fout, int *numOpclasses)
3651 {
3652         PGresult   *res;
3653         int                     ntups;
3654         int                     i;
3655         PQExpBuffer query = createPQExpBuffer();
3656         OpclassInfo *opcinfo;
3657         int                     i_tableoid;
3658         int                     i_oid;
3659         int                     i_opcname;
3660         int                     i_opcnamespace;
3661         int                     i_rolname;
3662
3663         /*
3664          * find all opclasses, including builtin opclasses; we filter out
3665          * system-defined opclasses at dump-out time.
3666          */
3667
3668         /* Make sure we are in proper schema */
3669         selectSourceSchema(fout, "pg_catalog");
3670
3671         if (fout->remoteVersion >= 70300)
3672         {
3673                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3674                                                   "opcnamespace, "
3675                                                   "(%s opcowner) AS rolname "
3676                                                   "FROM pg_opclass",
3677                                                   username_subquery);
3678         }
3679         else if (fout->remoteVersion >= 70100)
3680         {
3681                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3682                                                   "0::oid AS opcnamespace, "
3683                                                   "''::name AS rolname "
3684                                                   "FROM pg_opclass");
3685         }
3686         else
3687         {
3688                 appendPQExpBuffer(query, "SELECT "
3689                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3690                                                   "oid, opcname, "
3691                                                   "0::oid AS opcnamespace, "
3692                                                   "''::name AS rolname "
3693                                                   "FROM pg_opclass");
3694         }
3695
3696         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3697
3698         ntups = PQntuples(res);
3699         *numOpclasses = ntups;
3700
3701         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3702
3703         i_tableoid = PQfnumber(res, "tableoid");
3704         i_oid = PQfnumber(res, "oid");
3705         i_opcname = PQfnumber(res, "opcname");
3706         i_opcnamespace = PQfnumber(res, "opcnamespace");
3707         i_rolname = PQfnumber(res, "rolname");
3708
3709         for (i = 0; i < ntups; i++)
3710         {
3711                 opcinfo[i].dobj.objType = DO_OPCLASS;
3712                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3713                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3714                 AssignDumpId(&opcinfo[i].dobj);
3715                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3716                 opcinfo[i].dobj.namespace =
3717                         findNamespace(fout,
3718                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3719                                                   opcinfo[i].dobj.catId.oid);
3720                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3721
3722                 /* Decide whether we want to dump it */
3723                 selectDumpableObject(&(opcinfo[i].dobj));
3724
3725                 if (fout->remoteVersion >= 70300)
3726                 {
3727                         if (strlen(opcinfo[i].rolname) == 0)
3728                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3729                                                   opcinfo[i].dobj.name);
3730                 }
3731         }
3732
3733         PQclear(res);
3734
3735         destroyPQExpBuffer(query);
3736
3737         return opcinfo;
3738 }
3739
3740 /*
3741  * getOpfamilies:
3742  *        read all opfamilies in the system catalogs and return them in the
3743  * OpfamilyInfo* structure
3744  *
3745  *      numOpfamilies is set to the number of opfamilies read in
3746  */
3747 OpfamilyInfo *
3748 getOpfamilies(Archive *fout, int *numOpfamilies)
3749 {
3750         PGresult   *res;
3751         int                     ntups;
3752         int                     i;
3753         PQExpBuffer query;
3754         OpfamilyInfo *opfinfo;
3755         int                     i_tableoid;
3756         int                     i_oid;
3757         int                     i_opfname;
3758         int                     i_opfnamespace;
3759         int                     i_rolname;
3760
3761         /* Before 8.3, there is no separate concept of opfamilies */
3762         if (fout->remoteVersion < 80300)
3763         {
3764                 *numOpfamilies = 0;
3765                 return NULL;
3766         }
3767
3768         query = createPQExpBuffer();
3769
3770         /*
3771          * find all opfamilies, including builtin opfamilies; we filter out
3772          * system-defined opfamilies at dump-out time.
3773          */
3774
3775         /* Make sure we are in proper schema */
3776         selectSourceSchema(fout, "pg_catalog");
3777
3778         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3779                                           "opfnamespace, "
3780                                           "(%s opfowner) AS rolname "
3781                                           "FROM pg_opfamily",
3782                                           username_subquery);
3783
3784         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3785
3786         ntups = PQntuples(res);
3787         *numOpfamilies = ntups;
3788
3789         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3790
3791         i_tableoid = PQfnumber(res, "tableoid");
3792         i_oid = PQfnumber(res, "oid");
3793         i_opfname = PQfnumber(res, "opfname");
3794         i_opfnamespace = PQfnumber(res, "opfnamespace");
3795         i_rolname = PQfnumber(res, "rolname");
3796
3797         for (i = 0; i < ntups; i++)
3798         {
3799                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3800                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3801                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3802                 AssignDumpId(&opfinfo[i].dobj);
3803                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3804                 opfinfo[i].dobj.namespace =
3805                         findNamespace(fout,
3806                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3807                                                   opfinfo[i].dobj.catId.oid);
3808                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3809
3810                 /* Decide whether we want to dump it */
3811                 selectDumpableObject(&(opfinfo[i].dobj));
3812
3813                 if (fout->remoteVersion >= 70300)
3814                 {
3815                         if (strlen(opfinfo[i].rolname) == 0)
3816                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3817                                                   opfinfo[i].dobj.name);
3818                 }
3819         }
3820
3821         PQclear(res);
3822
3823         destroyPQExpBuffer(query);
3824
3825         return opfinfo;
3826 }
3827
3828 /*
3829  * getAggregates:
3830  *        read all the user-defined aggregates in the system catalogs and
3831  * return them in the AggInfo* structure
3832  *
3833  * numAggs is set to the number of aggregates read in
3834  */
3835 AggInfo *
3836 getAggregates(Archive *fout, int *numAggs)
3837 {
3838         PGresult   *res;
3839         int                     ntups;
3840         int                     i;
3841         PQExpBuffer query = createPQExpBuffer();
3842         AggInfo    *agginfo;
3843         int                     i_tableoid;
3844         int                     i_oid;
3845         int                     i_aggname;
3846         int                     i_aggnamespace;
3847         int                     i_pronargs;
3848         int                     i_proargtypes;
3849         int                     i_rolname;
3850         int                     i_aggacl;
3851         int                     i_proiargs;
3852
3853         /* Make sure we are in proper schema */
3854         selectSourceSchema(fout, "pg_catalog");
3855
3856         /*
3857          * Find all user-defined aggregates.  See comment in getFuncs() for the
3858          * rationale behind the filtering logic.
3859          */
3860
3861         if (fout->remoteVersion >= 80400)
3862         {
3863                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3864                                                   "pronamespace AS aggnamespace, "
3865                                                   "pronargs, proargtypes, "
3866                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
3867                                                   "(%s proowner) AS rolname, "
3868                                                   "proacl AS aggacl "
3869                                                   "FROM pg_proc p "
3870                                                   "WHERE proisagg AND ("
3871                                                   "pronamespace != "
3872                                                   "(SELECT oid FROM pg_namespace "
3873                                                   "WHERE nspname = 'pg_catalog')",
3874                                                   username_subquery);
3875                 if (binary_upgrade && fout->remoteVersion >= 90100)
3876                         appendPQExpBuffer(query,
3877                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3878                                                           "classid = 'pg_proc'::regclass AND "
3879                                                           "objid = p.oid AND "
3880                                                           "refclassid = 'pg_extension'::regclass AND "
3881                                                           "deptype = 'e')");
3882                 appendPQExpBuffer(query, ")");
3883         }
3884         else if (fout->remoteVersion >= 80200)
3885         {
3886                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3887                                                   "pronamespace AS aggnamespace, "
3888                                                   "pronargs, proargtypes, "
3889                                                   "NULL::text AS proiargs,"
3890                                                   "(%s proowner) AS rolname, "
3891                                                   "proacl AS aggacl "
3892                                                   "FROM pg_proc p "
3893                                                   "WHERE proisagg AND ("
3894                                                   "pronamespace != "
3895                                                   "(SELECT oid FROM pg_namespace "
3896                                                   "WHERE nspname = 'pg_catalog'))",
3897                                                   username_subquery);
3898         }
3899         else if (fout->remoteVersion >= 70300)
3900         {
3901                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3902                                                   "pronamespace AS aggnamespace, "
3903                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3904                                                   "proargtypes, "
3905                                                   "NULL::text AS proiargs, "
3906                                                   "(%s proowner) AS rolname, "
3907                                                   "proacl AS aggacl "
3908                                                   "FROM pg_proc "
3909                                                   "WHERE proisagg "
3910                                                   "AND pronamespace != "
3911                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3912                                                   username_subquery);
3913         }
3914         else if (fout->remoteVersion >= 70100)
3915         {
3916                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3917                                                   "0::oid AS aggnamespace, "
3918                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3919                                                   "aggbasetype AS proargtypes, "
3920                                                   "NULL::text AS proiargs, "
3921                                                   "(%s aggowner) AS rolname, "
3922                                                   "'{=X}' AS aggacl "
3923                                                   "FROM pg_aggregate "
3924                                                   "where oid > '%u'::oid",
3925                                                   username_subquery,
3926                                                   g_last_builtin_oid);
3927         }
3928         else
3929         {
3930                 appendPQExpBuffer(query, "SELECT "
3931                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3932                                                   "oid, aggname, "
3933                                                   "0::oid AS aggnamespace, "
3934                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3935                                                   "aggbasetype AS proargtypes, "
3936                                                   "NULL::text AS proiargs, "
3937                                                   "(%s aggowner) AS rolname, "
3938                                                   "'{=X}' AS aggacl "
3939                                                   "FROM pg_aggregate "
3940                                                   "where oid > '%u'::oid",
3941                                                   username_subquery,
3942                                                   g_last_builtin_oid);
3943         }
3944
3945         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3946
3947         ntups = PQntuples(res);
3948         *numAggs = ntups;
3949
3950         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3951
3952         i_tableoid = PQfnumber(res, "tableoid");
3953         i_oid = PQfnumber(res, "oid");
3954         i_aggname = PQfnumber(res, "aggname");
3955         i_aggnamespace = PQfnumber(res, "aggnamespace");
3956         i_pronargs = PQfnumber(res, "pronargs");
3957         i_proargtypes = PQfnumber(res, "proargtypes");
3958         i_rolname = PQfnumber(res, "rolname");
3959         i_aggacl = PQfnumber(res, "aggacl");
3960         i_proiargs = PQfnumber(res, "proiargs");
3961
3962         for (i = 0; i < ntups; i++)
3963         {
3964                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3965                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3966                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3967                 AssignDumpId(&agginfo[i].aggfn.dobj);
3968                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3969                 agginfo[i].aggfn.dobj.namespace =
3970                         findNamespace(fout,
3971                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
3972                                                   agginfo[i].aggfn.dobj.catId.oid);
3973                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3974                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3975                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3976                                           agginfo[i].aggfn.dobj.name);
3977                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3978                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3979                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3980                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
3981                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3982                 if (agginfo[i].aggfn.nargs == 0)
3983                         agginfo[i].aggfn.argtypes = NULL;
3984                 else
3985                 {
3986                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3987                         if (fout->remoteVersion >= 70300)
3988                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3989                                                           agginfo[i].aggfn.argtypes,
3990                                                           agginfo[i].aggfn.nargs);
3991                         else
3992                                 /* it's just aggbasetype */
3993                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3994                 }
3995
3996                 /* Decide whether we want to dump it */
3997                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3998         }
3999
4000         PQclear(res);
4001
4002         destroyPQExpBuffer(query);
4003
4004         return agginfo;
4005 }
4006
4007 /*
4008  * getFuncs:
4009  *        read all the user-defined functions in the system catalogs and
4010  * return them in the FuncInfo* structure
4011  *
4012  * numFuncs is set to the number of functions read in
4013  */
4014 FuncInfo *
4015 getFuncs(Archive *fout, int *numFuncs)
4016 {
4017         PGresult   *res;
4018         int                     ntups;
4019         int                     i;
4020         PQExpBuffer query = createPQExpBuffer();
4021         FuncInfo   *finfo;
4022         int                     i_tableoid;
4023         int                     i_oid;
4024         int                     i_proname;
4025         int                     i_pronamespace;
4026         int                     i_rolname;
4027         int                     i_prolang;
4028         int                     i_pronargs;
4029         int                     i_proargtypes;
4030         int                     i_prorettype;
4031         int                     i_proacl;
4032         int                     i_proiargs;
4033
4034         /* Make sure we are in proper schema */
4035         selectSourceSchema(fout, "pg_catalog");
4036
4037         /*
4038          * Find all user-defined functions.  Normally we can exclude functions in
4039          * pg_catalog, which is worth doing since there are several thousand of
4040          * 'em.  However, there are some extensions that create functions in
4041          * pg_catalog.  In normal dumps we can still ignore those --- but in
4042          * binary-upgrade mode, we must dump the member objects of the extension,
4043          * so be sure to fetch any such functions.
4044          *
4045          * Also, in 9.2 and up, exclude functions that are internally dependent on
4046          * something else, since presumably those will be created as a result of
4047          * creating the something else.  This currently only acts to suppress
4048          * constructor functions for range types.  Note that this is OK only
4049          * because the constructors don't have any dependencies the range type
4050          * doesn't have; otherwise we might not get creation ordering correct.
4051          */
4052
4053         if (fout->remoteVersion >= 80400)
4054         {
4055                 appendPQExpBuffer(query,
4056                                                   "SELECT tableoid, oid, proname, prolang, "
4057                                                   "pronargs, proargtypes, prorettype, proacl, "
4058                                                   "pronamespace, "
4059                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4060                                                   "(%s proowner) AS rolname "
4061                                                   "FROM pg_proc p "
4062                                                   "WHERE NOT proisagg AND ("
4063                                                   "pronamespace != "
4064                                                   "(SELECT oid FROM pg_namespace "
4065                                                   "WHERE nspname = 'pg_catalog')",
4066                                                   username_subquery);
4067                 if (fout->remoteVersion >= 90200)
4068                         appendPQExpBuffer(query,
4069                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4070                                                           "WHERE classid = 'pg_proc'::regclass AND "
4071                                                           "objid = p.oid AND deptype = 'i')");
4072                 if (binary_upgrade && fout->remoteVersion >= 90100)
4073                         appendPQExpBuffer(query,
4074                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4075                                                           "classid = 'pg_proc'::regclass AND "
4076                                                           "objid = p.oid AND "
4077                                                           "refclassid = 'pg_extension'::regclass AND "
4078                                                           "deptype = 'e')");
4079                 appendPQExpBuffer(query, ")");
4080         }
4081         else if (fout->remoteVersion >= 70300)
4082         {
4083                 appendPQExpBuffer(query,
4084                                                   "SELECT tableoid, oid, proname, prolang, "
4085                                                   "pronargs, proargtypes, prorettype, proacl, "
4086                                                   "pronamespace, "
4087                                                   "NULL::text AS proiargs,"
4088                                                   "(%s proowner) AS rolname "
4089                                                   "FROM pg_proc p "
4090                                                   "WHERE NOT proisagg AND ("
4091                                                   "pronamespace != "
4092                                                   "(SELECT oid FROM pg_namespace "
4093                                                   "WHERE nspname = 'pg_catalog'))",
4094                                                   username_subquery);
4095         }
4096         else if (fout->remoteVersion >= 70100)
4097         {
4098                 appendPQExpBuffer(query,
4099                                                   "SELECT tableoid, oid, proname, prolang, "
4100                                                   "pronargs, proargtypes, prorettype, "
4101                                                   "'{=X}' AS proacl, "
4102                                                   "0::oid AS pronamespace, "
4103                                                   "NULL::text AS proiargs,"
4104                                                   "(%s proowner) AS rolname "
4105                                                   "FROM pg_proc "
4106                                                   "WHERE pg_proc.oid > '%u'::oid",
4107                                                   username_subquery,
4108                                                   g_last_builtin_oid);
4109         }
4110         else
4111         {
4112                 appendPQExpBuffer(query,
4113                                                   "SELECT "
4114                                                   "(SELECT oid FROM pg_class "
4115                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4116                                                   "oid, proname, prolang, "
4117                                                   "pronargs, proargtypes, prorettype, "
4118                                                   "'{=X}' AS proacl, "
4119                                                   "0::oid AS pronamespace, "
4120                                                   "NULL::text AS proiargs,"
4121                                                   "(%s proowner) AS rolname "
4122                                                   "FROM pg_proc "
4123                                                   "where pg_proc.oid > '%u'::oid",
4124                                                   username_subquery,
4125                                                   g_last_builtin_oid);
4126         }
4127
4128         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4129
4130         ntups = PQntuples(res);
4131
4132         *numFuncs = ntups;
4133
4134         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4135
4136         i_tableoid = PQfnumber(res, "tableoid");
4137         i_oid = PQfnumber(res, "oid");
4138         i_proname = PQfnumber(res, "proname");
4139         i_pronamespace = PQfnumber(res, "pronamespace");
4140         i_rolname = PQfnumber(res, "rolname");
4141         i_prolang = PQfnumber(res, "prolang");
4142         i_pronargs = PQfnumber(res, "pronargs");
4143         i_proargtypes = PQfnumber(res, "proargtypes");
4144         i_prorettype = PQfnumber(res, "prorettype");
4145         i_proacl = PQfnumber(res, "proacl");
4146         i_proiargs = PQfnumber(res, "proiargs");
4147
4148         for (i = 0; i < ntups; i++)
4149         {
4150                 finfo[i].dobj.objType = DO_FUNC;
4151                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4152                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4153                 AssignDumpId(&finfo[i].dobj);
4154                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4155                 finfo[i].dobj.namespace =
4156                         findNamespace(fout,
4157                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4158                                                   finfo[i].dobj.catId.oid);
4159                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4160                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4161                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4162                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4163                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4164                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4165                 if (finfo[i].nargs == 0)
4166                         finfo[i].argtypes = NULL;
4167                 else
4168                 {
4169                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4170                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4171                                                   finfo[i].argtypes, finfo[i].nargs);
4172                 }
4173
4174                 /* Decide whether we want to dump it */
4175                 selectDumpableObject(&(finfo[i].dobj));
4176
4177                 if (strlen(finfo[i].rolname) == 0)
4178                         write_msg(NULL,
4179                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4180                                           finfo[i].dobj.name);
4181         }
4182
4183         PQclear(res);
4184
4185         destroyPQExpBuffer(query);
4186
4187         return finfo;
4188 }
4189
4190 /*
4191  * getTables
4192  *        read all the user-defined tables (no indexes, no catalogs)
4193  * in the system catalogs return them in the TableInfo* structure
4194  *
4195  * numTables is set to the number of tables read in
4196  */
4197 TableInfo *
4198 getTables(Archive *fout, int *numTables)
4199 {
4200         PGresult   *res;
4201         int                     ntups;
4202         int                     i;
4203         PQExpBuffer query = createPQExpBuffer();
4204         TableInfo  *tblinfo;
4205         int                     i_reltableoid;
4206         int                     i_reloid;
4207         int                     i_relname;
4208         int                     i_relnamespace;
4209         int                     i_relkind;
4210         int                     i_relacl;
4211         int                     i_rolname;
4212         int                     i_relchecks;
4213         int                     i_relhastriggers;
4214         int                     i_relhasindex;
4215         int                     i_relhasrules;
4216         int                     i_relhasoids;
4217         int                     i_relfrozenxid;
4218         int                     i_toastoid;
4219         int                     i_toastfrozenxid;
4220         int                     i_relpersistence;
4221         int                     i_isscannable;
4222         int                     i_owning_tab;
4223         int                     i_owning_col;
4224         int                     i_reltablespace;
4225         int                     i_reloptions;
4226         int                     i_toastreloptions;
4227         int                     i_reloftype;
4228         int                     i_relpages;
4229
4230         /* Make sure we are in proper schema */
4231         selectSourceSchema(fout, "pg_catalog");
4232
4233         /*
4234          * Find all the tables and table-like objects.
4235          *
4236          * We include system catalogs, so that we can work if a user table is
4237          * defined to inherit from a system catalog (pretty weird, but...)
4238          *
4239          * We ignore relations that are not ordinary tables, sequences, views,
4240          * materialized views, composite types, or foreign tables.
4241          *
4242          * Composite-type table entries won't be dumped as such, but we have to
4243          * make a DumpableObject for them so that we can track dependencies of the
4244          * composite type (pg_depend entries for columns of the composite type
4245          * link to the pg_class entry not the pg_type entry).
4246          *
4247          * Note: in this phase we should collect only a minimal amount of
4248          * information about each table, basically just enough to decide if it is
4249          * interesting. We must fetch all tables in this phase because otherwise
4250          * we cannot correctly identify inherited columns, owned sequences, etc.
4251          */
4252
4253         if (fout->remoteVersion >= 90300)
4254         {
4255                 /*
4256                  * Left join to pick up dependency info linking sequences to their
4257                  * owning column, if any (note this dependency is AUTO as of 8.2)
4258                  */
4259                 appendPQExpBuffer(query,
4260                                                   "SELECT c.tableoid, c.oid, c.relname, "
4261                                                   "c.relacl, c.relkind, c.relnamespace, "
4262                                                   "(%s c.relowner) AS rolname, "
4263                                                   "c.relchecks, c.relhastriggers, "
4264                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4265                                                   "c.relfrozenxid, tc.oid AS toid, "
4266                                                   "tc.relfrozenxid AS tfrozenxid, "
4267                                                   "c.relpersistence, "
4268                                                   "CASE WHEN c.relkind = '%c' THEN pg_relation_is_scannable(c.oid) ELSE 't'::bool END as isscannable, "
4269                                                   "c.relpages, "
4270                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4271                                                   "d.refobjid AS owning_tab, "
4272                                                   "d.refobjsubid AS owning_col, "
4273                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4274                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4275                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4276                                                   "FROM pg_class c "
4277                                                   "LEFT JOIN pg_depend d ON "
4278                                                   "(c.relkind = '%c' AND "
4279                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4280                                                   "d.objsubid = 0 AND "
4281                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4282                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4283                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4284                                                   "ORDER BY c.oid",
4285                                                   username_subquery,
4286                                                   RELKIND_MATVIEW,
4287                                                   RELKIND_SEQUENCE,
4288                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4289                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4290                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4291         }
4292         else if (fout->remoteVersion >= 90100)
4293         {
4294                 /*
4295                  * Left join to pick up dependency info linking sequences to their
4296                  * owning column, if any (note this dependency is AUTO as of 8.2)
4297                  */
4298                 appendPQExpBuffer(query,
4299                                                   "SELECT c.tableoid, c.oid, c.relname, "
4300                                                   "c.relacl, c.relkind, c.relnamespace, "
4301                                                   "(%s c.relowner) AS rolname, "
4302                                                   "c.relchecks, c.relhastriggers, "
4303                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4304                                                   "c.relfrozenxid, tc.oid AS toid, "
4305                                                   "tc.relfrozenxid AS tfrozenxid, "
4306                                                   "c.relpersistence, 't'::bool as isscannable, "
4307                                                   "c.relpages, "
4308                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4309                                                   "d.refobjid AS owning_tab, "
4310                                                   "d.refobjsubid AS owning_col, "
4311                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4312                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4313                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4314                                                   "FROM pg_class c "
4315                                                   "LEFT JOIN pg_depend d ON "
4316                                                   "(c.relkind = '%c' AND "
4317                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4318                                                   "d.objsubid = 0 AND "
4319                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4320                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4321                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4322                                                   "ORDER BY c.oid",
4323                                                   username_subquery,
4324                                                   RELKIND_SEQUENCE,
4325                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4326                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4327                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4328         }
4329         else if (fout->remoteVersion >= 90000)
4330         {
4331                 /*
4332                  * Left join to pick up dependency info linking sequences to their
4333                  * owning column, if any (note this dependency is AUTO as of 8.2)
4334                  */
4335                 appendPQExpBuffer(query,
4336                                                   "SELECT c.tableoid, c.oid, c.relname, "
4337                                                   "c.relacl, c.relkind, c.relnamespace, "
4338                                                   "(%s c.relowner) AS rolname, "
4339                                                   "c.relchecks, c.relhastriggers, "
4340                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4341                                                   "c.relfrozenxid, tc.oid AS toid, "
4342                                                   "tc.relfrozenxid AS tfrozenxid, "
4343                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4344                                                   "c.relpages, "
4345                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4346                                                   "d.refobjid AS owning_tab, "
4347                                                   "d.refobjsubid AS owning_col, "
4348                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4349                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4350                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4351                                                   "FROM pg_class c "
4352                                                   "LEFT JOIN pg_depend d ON "
4353                                                   "(c.relkind = '%c' AND "
4354                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4355                                                   "d.objsubid = 0 AND "
4356                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4357                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4358                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4359                                                   "ORDER BY c.oid",
4360                                                   username_subquery,
4361                                                   RELKIND_SEQUENCE,
4362                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4363                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4364         }
4365         else if (fout->remoteVersion >= 80400)
4366         {
4367                 /*
4368                  * Left join to pick up dependency info linking sequences to their
4369                  * owning column, if any (note this dependency is AUTO as of 8.2)
4370                  */
4371                 appendPQExpBuffer(query,
4372                                                   "SELECT c.tableoid, c.oid, c.relname, "
4373                                                   "c.relacl, c.relkind, c.relnamespace, "
4374                                                   "(%s c.relowner) AS rolname, "
4375                                                   "c.relchecks, c.relhastriggers, "
4376                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4377                                                   "c.relfrozenxid, tc.oid AS toid, "
4378                                                   "tc.relfrozenxid AS tfrozenxid, "
4379                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4380                                                   "c.relpages, "
4381                                                   "NULL AS reloftype, "
4382                                                   "d.refobjid AS owning_tab, "
4383                                                   "d.refobjsubid AS owning_col, "
4384                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4385                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4386                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4387                                                   "FROM pg_class c "
4388                                                   "LEFT JOIN pg_depend d ON "
4389                                                   "(c.relkind = '%c' AND "
4390                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4391                                                   "d.objsubid = 0 AND "
4392                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4393                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4394                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4395                                                   "ORDER BY c.oid",
4396                                                   username_subquery,
4397                                                   RELKIND_SEQUENCE,
4398                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4399                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4400         }
4401         else if (fout->remoteVersion >= 80200)
4402         {
4403                 /*
4404                  * Left join to pick up dependency info linking sequences to their
4405                  * owning column, if any (note this dependency is AUTO as of 8.2)
4406                  */
4407                 appendPQExpBuffer(query,
4408                                                   "SELECT c.tableoid, c.oid, c.relname, "
4409                                                   "c.relacl, c.relkind, c.relnamespace, "
4410                                                   "(%s c.relowner) AS rolname, "
4411                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4412                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4413                                                   "c.relfrozenxid, tc.oid AS toid, "
4414                                                   "tc.relfrozenxid AS tfrozenxid, "
4415                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4416                                                   "c.relpages, "
4417                                                   "NULL AS reloftype, "
4418                                                   "d.refobjid AS owning_tab, "
4419                                                   "d.refobjsubid AS owning_col, "
4420                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4421                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4422                                                   "NULL AS toast_reloptions "
4423                                                   "FROM pg_class c "
4424                                                   "LEFT JOIN pg_depend d ON "
4425                                                   "(c.relkind = '%c' AND "
4426                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4427                                                   "d.objsubid = 0 AND "
4428                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4429                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4430                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4431                                                   "ORDER BY c.oid",
4432                                                   username_subquery,
4433                                                   RELKIND_SEQUENCE,
4434                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4435                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4436         }
4437         else if (fout->remoteVersion >= 80000)
4438         {
4439                 /*
4440                  * Left join to pick up dependency info linking sequences to their
4441                  * owning column, if any
4442                  */
4443                 appendPQExpBuffer(query,
4444                                                   "SELECT c.tableoid, c.oid, relname, "
4445                                                   "relacl, relkind, relnamespace, "
4446                                                   "(%s relowner) AS rolname, "
4447                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4448                                                   "relhasindex, relhasrules, relhasoids, "
4449                                                   "0 AS relfrozenxid, "
4450                                                   "0 AS toid, "
4451                                                   "0 AS tfrozenxid, "
4452                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4453                                                   "relpages, "
4454                                                   "NULL AS reloftype, "
4455                                                   "d.refobjid AS owning_tab, "
4456                                                   "d.refobjsubid AS owning_col, "
4457                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4458                                                   "NULL AS reloptions, "
4459                                                   "NULL AS toast_reloptions "
4460                                                   "FROM pg_class c "
4461                                                   "LEFT JOIN pg_depend d ON "
4462                                                   "(c.relkind = '%c' AND "
4463                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4464                                                   "d.objsubid = 0 AND "
4465                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4466                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4467                                                   "ORDER BY c.oid",
4468                                                   username_subquery,
4469                                                   RELKIND_SEQUENCE,
4470                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4471                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4472         }
4473         else if (fout->remoteVersion >= 70300)
4474         {
4475                 /*
4476                  * Left join to pick up dependency info linking sequences to their
4477                  * owning column, if any
4478                  */
4479                 appendPQExpBuffer(query,
4480                                                   "SELECT c.tableoid, c.oid, relname, "
4481                                                   "relacl, relkind, relnamespace, "
4482                                                   "(%s relowner) AS rolname, "
4483                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4484                                                   "relhasindex, relhasrules, relhasoids, "
4485                                                   "0 AS relfrozenxid, "
4486                                                   "0 AS toid, "
4487                                                   "0 AS tfrozenxid, "
4488                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4489                                                   "relpages, "
4490                                                   "NULL AS reloftype, "
4491                                                   "d.refobjid AS owning_tab, "
4492                                                   "d.refobjsubid AS owning_col, "
4493                                                   "NULL AS reltablespace, "
4494                                                   "NULL AS reloptions, "
4495                                                   "NULL AS toast_reloptions "
4496                                                   "FROM pg_class c "
4497                                                   "LEFT JOIN pg_depend d ON "
4498                                                   "(c.relkind = '%c' AND "
4499                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4500                                                   "d.objsubid = 0 AND "
4501                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4502                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4503                                                   "ORDER BY c.oid",
4504                                                   username_subquery,
4505                                                   RELKIND_SEQUENCE,
4506                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4507                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4508         }
4509         else if (fout->remoteVersion >= 70200)
4510         {
4511                 appendPQExpBuffer(query,
4512                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4513                                                   "0::oid AS relnamespace, "
4514                                                   "(%s relowner) AS rolname, "
4515                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4516                                                   "relhasindex, relhasrules, relhasoids, "
4517                                                   "0 AS relfrozenxid, "
4518                                                   "0 AS toid, "
4519                                                   "0 AS tfrozenxid, "
4520                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4521                                                   "relpages, "
4522                                                   "NULL AS reloftype, "
4523                                                   "NULL::oid AS owning_tab, "
4524                                                   "NULL::int4 AS owning_col, "
4525                                                   "NULL AS reltablespace, "
4526                                                   "NULL AS reloptions, "
4527                                                   "NULL AS toast_reloptions "
4528                                                   "FROM pg_class "
4529                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4530                                                   "ORDER BY oid",
4531                                                   username_subquery,
4532                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4533         }
4534         else if (fout->remoteVersion >= 70100)
4535         {
4536                 /* all tables have oids in 7.1 */
4537                 appendPQExpBuffer(query,
4538                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4539                                                   "0::oid AS relnamespace, "
4540                                                   "(%s relowner) AS rolname, "
4541                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4542                                                   "relhasindex, relhasrules, "
4543                                                   "'t'::bool AS relhasoids, "
4544                                                   "0 AS relfrozenxid, "
4545                                                   "0 AS toid, "
4546                                                   "0 AS tfrozenxid, "
4547                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4548                                                   "relpages, "
4549                                                   "NULL AS reloftype, "
4550                                                   "NULL::oid AS owning_tab, "
4551                                                   "NULL::int4 AS owning_col, "
4552                                                   "NULL AS reltablespace, "
4553                                                   "NULL AS reloptions, "
4554                                                   "NULL AS toast_reloptions "
4555                                                   "FROM pg_class "
4556                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4557                                                   "ORDER BY oid",
4558                                                   username_subquery,
4559                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4560         }
4561         else
4562         {
4563                 /*
4564                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4565                  * have a view by looking for a rule in pg_rewrite.
4566                  */
4567                 appendPQExpBuffer(query,
4568                                                   "SELECT "
4569                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4570                                                   "oid, relname, relacl, "
4571                                                   "CASE WHEN relhasrules and relkind = 'r' "
4572                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4573                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4574                                                   "THEN '%c'::\"char\" "
4575                                                   "ELSE relkind END AS relkind,"
4576                                                   "0::oid AS relnamespace, "
4577                                                   "(%s relowner) AS rolname, "
4578                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4579                                                   "relhasindex, relhasrules, "
4580                                                   "'t'::bool AS relhasoids, "
4581                                                   "0 as relfrozenxid, "
4582                                                   "0 AS toid, "
4583                                                   "0 AS tfrozenxid, "
4584                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4585                                                   "0 AS relpages, "
4586                                                   "NULL AS reloftype, "
4587                                                   "NULL::oid AS owning_tab, "
4588                                                   "NULL::int4 AS owning_col, "
4589                                                   "NULL AS reltablespace, "
4590                                                   "NULL AS reloptions, "
4591                                                   "NULL AS toast_reloptions "
4592                                                   "FROM pg_class c "
4593                                                   "WHERE relkind IN ('%c', '%c') "
4594                                                   "ORDER BY oid",
4595                                                   RELKIND_VIEW,
4596                                                   username_subquery,
4597                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4598         }
4599
4600         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4601
4602         ntups = PQntuples(res);
4603
4604         *numTables = ntups;
4605
4606         /*
4607          * Extract data from result and lock dumpable tables.  We do the locking
4608          * before anything else, to minimize the window wherein a table could
4609          * disappear under us.
4610          *
4611          * Note that we have to save info about all tables here, even when dumping
4612          * only one, because we don't yet know which tables might be inheritance
4613          * ancestors of the target table.
4614          */
4615         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
4616
4617         i_reltableoid = PQfnumber(res, "tableoid");
4618         i_reloid = PQfnumber(res, "oid");
4619         i_relname = PQfnumber(res, "relname");
4620         i_relnamespace = PQfnumber(res, "relnamespace");
4621         i_relacl = PQfnumber(res, "relacl");
4622         i_relkind = PQfnumber(res, "relkind");
4623         i_rolname = PQfnumber(res, "rolname");
4624         i_relchecks = PQfnumber(res, "relchecks");
4625         i_relhastriggers = PQfnumber(res, "relhastriggers");
4626         i_relhasindex = PQfnumber(res, "relhasindex");
4627         i_relhasrules = PQfnumber(res, "relhasrules");
4628         i_relhasoids = PQfnumber(res, "relhasoids");
4629         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4630         i_toastoid = PQfnumber(res, "toid");
4631         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4632         i_relpersistence = PQfnumber(res, "relpersistence");
4633         i_isscannable = PQfnumber(res, "isscannable");
4634         i_relpages = PQfnumber(res, "relpages");
4635         i_owning_tab = PQfnumber(res, "owning_tab");
4636         i_owning_col = PQfnumber(res, "owning_col");
4637         i_reltablespace = PQfnumber(res, "reltablespace");
4638         i_reloptions = PQfnumber(res, "reloptions");
4639         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4640         i_reloftype = PQfnumber(res, "reloftype");
4641
4642         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4643         {
4644                 /*
4645                  * Arrange to fail instead of waiting forever for a table lock.
4646                  *
4647                  * NB: this coding assumes that the only queries issued within the
4648                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4649                  * applied to other things too.
4650                  */
4651                 resetPQExpBuffer(query);
4652                 appendPQExpBuffer(query, "SET statement_timeout = ");
4653                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4654                 ExecuteSqlStatement(fout, query->data);
4655         }
4656
4657         for (i = 0; i < ntups; i++)
4658         {
4659                 tblinfo[i].dobj.objType = DO_TABLE;
4660                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4661                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4662                 AssignDumpId(&tblinfo[i].dobj);
4663                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4664                 tblinfo[i].dobj.namespace =
4665                         findNamespace(fout,
4666                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4667                                                   tblinfo[i].dobj.catId.oid);
4668                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4669                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4670                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4671                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4672                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4673                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4674                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4675                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4676                 tblinfo[i].isscannable = (strcmp(PQgetvalue(res, i, i_isscannable), "t") == 0);
4677                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
4678                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4679                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4680                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4681                 if (PQgetisnull(res, i, i_reloftype))
4682                         tblinfo[i].reloftype = NULL;
4683                 else
4684                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4685                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4686                 if (PQgetisnull(res, i, i_owning_tab))
4687                 {
4688                         tblinfo[i].owning_tab = InvalidOid;
4689                         tblinfo[i].owning_col = 0;
4690                 }
4691                 else
4692                 {
4693                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4694                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4695                 }
4696                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4697                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4698                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4699
4700                 /* other fields were zeroed above */
4701
4702                 /*
4703                  * Decide whether we want to dump this table.
4704                  */
4705                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4706                         tblinfo[i].dobj.dump = false;
4707                 else
4708                         selectDumpableTable(&tblinfo[i]);
4709                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4710
4711                 /*
4712                  * Read-lock target tables to make sure they aren't DROPPED or altered
4713                  * in schema before we get around to dumping them.
4714                  *
4715                  * Note that we don't explicitly lock parents of the target tables; we
4716                  * assume our lock on the child is enough to prevent schema
4717                  * alterations to parent tables.
4718                  *
4719                  * NOTE: it'd be kinda nice to lock other relations too, not only
4720                  * plain tables, but the backend doesn't presently allow that.
4721                  */
4722                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4723                 {
4724                         resetPQExpBuffer(query);
4725                         appendPQExpBuffer(query,
4726                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4727                                                           fmtQualifiedId(fout->remoteVersion,
4728                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4729                                                                                          tblinfo[i].dobj.name));
4730                         ExecuteSqlStatement(fout, query->data);
4731                 }
4732
4733                 /* Emit notice if join for owner failed */
4734                 if (strlen(tblinfo[i].rolname) == 0)
4735                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4736                                           tblinfo[i].dobj.name);
4737         }
4738
4739         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4740         {
4741                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4742         }
4743
4744         PQclear(res);
4745
4746         destroyPQExpBuffer(query);
4747
4748         return tblinfo;
4749 }
4750
4751 /*
4752  * getOwnedSeqs
4753  *        identify owned sequences and mark them as dumpable if owning table is
4754  *
4755  * We used to do this in getTables(), but it's better to do it after the
4756  * index used by findTableByOid() has been set up.
4757  */
4758 void
4759 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4760 {
4761         int                     i;
4762
4763         /*
4764          * Force sequences that are "owned" by table columns to be dumped whenever
4765          * their owning table is being dumped.
4766          */
4767         for (i = 0; i < numTables; i++)
4768         {
4769                 TableInfo  *seqinfo = &tblinfo[i];
4770                 TableInfo  *owning_tab;
4771
4772                 if (!OidIsValid(seqinfo->owning_tab))
4773                         continue;                       /* not an owned sequence */
4774                 if (seqinfo->dobj.dump)
4775                         continue;                       /* no need to search */
4776                 owning_tab = findTableByOid(seqinfo->owning_tab);
4777                 if (owning_tab && owning_tab->dobj.dump)
4778                 {
4779                         seqinfo->interesting = true;
4780                         seqinfo->dobj.dump = true;
4781                 }
4782         }
4783 }
4784
4785 /*
4786  * getInherits
4787  *        read all the inheritance information
4788  * from the system catalogs return them in the InhInfo* structure
4789  *
4790  * numInherits is set to the number of pairs read in
4791  */
4792 InhInfo *
4793 getInherits(Archive *fout, int *numInherits)
4794 {
4795         PGresult   *res;
4796         int                     ntups;
4797         int                     i;
4798         PQExpBuffer query = createPQExpBuffer();
4799         InhInfo    *inhinfo;
4800
4801         int                     i_inhrelid;
4802         int                     i_inhparent;
4803
4804         /* Make sure we are in proper schema */
4805         selectSourceSchema(fout, "pg_catalog");
4806
4807         /* find all the inheritance information */
4808
4809         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4810
4811         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4812
4813         ntups = PQntuples(res);
4814
4815         *numInherits = ntups;
4816
4817         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4818
4819         i_inhrelid = PQfnumber(res, "inhrelid");
4820         i_inhparent = PQfnumber(res, "inhparent");
4821
4822         for (i = 0; i < ntups; i++)
4823         {
4824                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4825                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4826         }
4827
4828         PQclear(res);
4829
4830         destroyPQExpBuffer(query);
4831
4832         return inhinfo;
4833 }
4834
4835 /*
4836  * getIndexes
4837  *        get information about every index on a dumpable table
4838  *
4839  * Note: index data is not returned directly to the caller, but it
4840  * does get entered into the DumpableObject tables.
4841  */
4842 void
4843 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4844 {
4845         int                     i,
4846                                 j;
4847         PQExpBuffer query = createPQExpBuffer();
4848         PGresult   *res;
4849         IndxInfo   *indxinfo;
4850         ConstraintInfo *constrinfo;
4851         int                     i_tableoid,
4852                                 i_oid,
4853                                 i_indexname,
4854                                 i_indexdef,
4855                                 i_indnkeys,
4856                                 i_indkey,
4857                                 i_indisclustered,
4858                                 i_contype,
4859                                 i_conname,
4860                                 i_condeferrable,
4861                                 i_condeferred,
4862                                 i_contableoid,
4863                                 i_conoid,
4864                                 i_condef,
4865                                 i_tablespace,
4866                                 i_options,
4867                                 i_relpages;
4868         int                     ntups;
4869
4870         for (i = 0; i < numTables; i++)
4871         {
4872                 TableInfo  *tbinfo = &tblinfo[i];
4873
4874                 /* Only plain tables and materialized views have indexes. */
4875                 if (tbinfo->relkind != RELKIND_RELATION &&
4876                         tbinfo->relkind != RELKIND_MATVIEW)
4877                         continue;
4878                 if (!tbinfo->hasindex)
4879                         continue;
4880
4881                 /* Ignore indexes of tables not to be dumped */
4882                 if (!tbinfo->dobj.dump)
4883                         continue;
4884
4885                 if (g_verbose)
4886                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4887                                           tbinfo->dobj.name);
4888
4889                 /* Make sure we are in proper schema so indexdef is right */
4890                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4891
4892                 /*
4893                  * The point of the messy-looking outer join is to find a constraint
4894                  * that is related by an internal dependency link to the index. If we
4895                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4896                  * assume an index won't have more than one internal dependency.
4897                  *
4898                  * As of 9.0 we don't need to look at pg_depend but can check for a
4899                  * match to pg_constraint.conindid.  The check on conrelid is
4900                  * redundant but useful because that column is indexed while conindid
4901                  * is not.
4902                  */
4903                 resetPQExpBuffer(query);
4904                 if (fout->remoteVersion >= 90000)
4905                 {
4906                         /*
4907                          * the test on indisready is necessary in 9.2, and harmless in
4908                          * earlier/later versions
4909                          */
4910                         appendPQExpBuffer(query,
4911                                                           "SELECT t.tableoid, t.oid, "
4912                                                           "t.relname AS indexname, "
4913                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4914                                                           "t.relnatts AS indnkeys, "
4915                                                           "i.indkey, i.indisclustered, "
4916                                                           "t.relpages, "
4917                                                           "c.contype, c.conname, "
4918                                                           "c.condeferrable, c.condeferred, "
4919                                                           "c.tableoid AS contableoid, "
4920                                                           "c.oid AS conoid, "
4921                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4922                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4923                                                         "array_to_string(t.reloptions, ', ') AS options "
4924                                                           "FROM pg_catalog.pg_index i "
4925                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4926                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4927                                                           "ON (i.indrelid = c.conrelid AND "
4928                                                           "i.indexrelid = c.conindid AND "
4929                                                           "c.contype IN ('p','u','x')) "
4930                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4931                                                           "AND i.indisvalid AND i.indisready "
4932                                                           "ORDER BY indexname",
4933                                                           tbinfo->dobj.catId.oid);
4934                 }
4935                 else if (fout->remoteVersion >= 80200)
4936                 {
4937                         appendPQExpBuffer(query,
4938                                                           "SELECT t.tableoid, t.oid, "
4939                                                           "t.relname AS indexname, "
4940                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4941                                                           "t.relnatts AS indnkeys, "
4942                                                           "i.indkey, i.indisclustered, "
4943                                                           "t.relpages, "
4944                                                           "c.contype, c.conname, "
4945                                                           "c.condeferrable, c.condeferred, "
4946                                                           "c.tableoid AS contableoid, "
4947                                                           "c.oid AS conoid, "
4948                                                           "null AS condef, "
4949                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4950                                                         "array_to_string(t.reloptions, ', ') AS options "
4951                                                           "FROM pg_catalog.pg_index i "
4952                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4953                                                           "LEFT JOIN pg_catalog.pg_depend d "
4954                                                           "ON (d.classid = t.tableoid "
4955                                                           "AND d.objid = t.oid "
4956                                                           "AND d.deptype = 'i') "
4957                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4958                                                           "ON (d.refclassid = c.tableoid "
4959                                                           "AND d.refobjid = c.oid) "
4960                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4961                                                           "AND i.indisvalid "
4962                                                           "ORDER BY indexname",
4963                                                           tbinfo->dobj.catId.oid);
4964                 }
4965                 else if (fout->remoteVersion >= 80000)
4966                 {
4967                         appendPQExpBuffer(query,
4968                                                           "SELECT t.tableoid, t.oid, "
4969                                                           "t.relname AS indexname, "
4970                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4971                                                           "t.relnatts AS indnkeys, "
4972                                                           "i.indkey, i.indisclustered, "
4973                                                           "t.relpages, "
4974                                                           "c.contype, c.conname, "
4975                                                           "c.condeferrable, c.condeferred, "
4976                                                           "c.tableoid AS contableoid, "
4977                                                           "c.oid AS conoid, "
4978                                                           "null AS condef, "
4979                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4980                                                           "null AS options "
4981                                                           "FROM pg_catalog.pg_index i "
4982                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4983                                                           "LEFT JOIN pg_catalog.pg_depend d "
4984                                                           "ON (d.classid = t.tableoid "
4985                                                           "AND d.objid = t.oid "
4986                                                           "AND d.deptype = 'i') "
4987                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4988                                                           "ON (d.refclassid = c.tableoid "
4989                                                           "AND d.refobjid = c.oid) "
4990                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4991                                                           "ORDER BY indexname",
4992                                                           tbinfo->dobj.catId.oid);
4993                 }
4994                 else if (fout->remoteVersion >= 70300)
4995                 {
4996                         appendPQExpBuffer(query,
4997                                                           "SELECT t.tableoid, t.oid, "
4998                                                           "t.relname AS indexname, "
4999                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5000                                                           "t.relnatts AS indnkeys, "
5001                                                           "i.indkey, i.indisclustered, "
5002                                                           "t.relpages, "
5003                                                           "c.contype, c.conname, "
5004                                                           "c.condeferrable, c.condeferred, "
5005                                                           "c.tableoid AS contableoid, "
5006                                                           "c.oid AS conoid, "
5007                                                           "null AS condef, "
5008                                                           "NULL AS tablespace, "
5009                                                           "null AS options "
5010                                                           "FROM pg_catalog.pg_index i "
5011                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5012                                                           "LEFT JOIN pg_catalog.pg_depend d "
5013                                                           "ON (d.classid = t.tableoid "
5014                                                           "AND d.objid = t.oid "
5015                                                           "AND d.deptype = 'i') "
5016                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5017                                                           "ON (d.refclassid = c.tableoid "
5018                                                           "AND d.refobjid = c.oid) "
5019                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5020                                                           "ORDER BY indexname",
5021                                                           tbinfo->dobj.catId.oid);
5022                 }
5023                 else if (fout->remoteVersion >= 70100)
5024                 {
5025                         appendPQExpBuffer(query,
5026                                                           "SELECT t.tableoid, t.oid, "
5027                                                           "t.relname AS indexname, "
5028                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5029                                                           "t.relnatts AS indnkeys, "
5030                                                           "i.indkey, false AS indisclustered, "
5031                                                           "t.relpages, "
5032                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5033                                                           "ELSE '0'::char END AS contype, "
5034                                                           "t.relname AS conname, "
5035                                                           "false AS condeferrable, "
5036                                                           "false AS condeferred, "
5037                                                           "0::oid AS contableoid, "
5038                                                           "t.oid AS conoid, "
5039                                                           "null AS condef, "
5040                                                           "NULL AS tablespace, "
5041                                                           "null AS options "
5042                                                           "FROM pg_index i, pg_class t "
5043                                                           "WHERE t.oid = i.indexrelid "
5044                                                           "AND i.indrelid = '%u'::oid "
5045                                                           "ORDER BY indexname",
5046                                                           tbinfo->dobj.catId.oid);
5047                 }
5048                 else
5049                 {
5050                         appendPQExpBuffer(query,
5051                                                           "SELECT "
5052                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5053                                                           "t.oid, "
5054                                                           "t.relname AS indexname, "
5055                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5056                                                           "t.relnatts AS indnkeys, "
5057                                                           "i.indkey, false AS indisclustered, "
5058                                                           "t.relpages, "
5059                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5060                                                           "ELSE '0'::char END AS contype, "
5061                                                           "t.relname AS conname, "
5062                                                           "false AS condeferrable, "
5063                                                           "false AS condeferred, "
5064                                                           "0::oid AS contableoid, "
5065                                                           "t.oid AS conoid, "
5066                                                           "null AS condef, "
5067                                                           "NULL AS tablespace, "
5068                                                           "null AS options "
5069                                                           "FROM pg_index i, pg_class t "
5070                                                           "WHERE t.oid = i.indexrelid "
5071                                                           "AND i.indrelid = '%u'::oid "
5072                                                           "ORDER BY indexname",
5073                                                           tbinfo->dobj.catId.oid);
5074                 }
5075
5076                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5077
5078                 ntups = PQntuples(res);
5079
5080                 i_tableoid = PQfnumber(res, "tableoid");
5081                 i_oid = PQfnumber(res, "oid");
5082                 i_indexname = PQfnumber(res, "indexname");
5083                 i_indexdef = PQfnumber(res, "indexdef");
5084                 i_indnkeys = PQfnumber(res, "indnkeys");
5085                 i_indkey = PQfnumber(res, "indkey");
5086                 i_indisclustered = PQfnumber(res, "indisclustered");
5087                 i_relpages = PQfnumber(res, "relpages");
5088                 i_contype = PQfnumber(res, "contype");
5089                 i_conname = PQfnumber(res, "conname");
5090                 i_condeferrable = PQfnumber(res, "condeferrable");
5091                 i_condeferred = PQfnumber(res, "condeferred");
5092                 i_contableoid = PQfnumber(res, "contableoid");
5093                 i_conoid = PQfnumber(res, "conoid");
5094                 i_condef = PQfnumber(res, "condef");
5095                 i_tablespace = PQfnumber(res, "tablespace");
5096                 i_options = PQfnumber(res, "options");
5097
5098                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5099                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5100
5101                 for (j = 0; j < ntups; j++)
5102                 {
5103                         char            contype;
5104
5105                         indxinfo[j].dobj.objType = DO_INDEX;
5106                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5107                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5108                         AssignDumpId(&indxinfo[j].dobj);
5109                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5110                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5111                         indxinfo[j].indextable = tbinfo;
5112                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5113                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5114                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5115                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5116
5117                         /*
5118                          * In pre-7.4 releases, indkeys may contain more entries than
5119                          * indnkeys says (since indnkeys will be 1 for a functional
5120                          * index).      We don't actually care about this case since we don't
5121                          * examine indkeys except for indexes associated with PRIMARY and
5122                          * UNIQUE constraints, which are never functional indexes. But we
5123                          * have to allocate enough space to keep parseOidArray from
5124                          * complaining.
5125                          */
5126                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5127                         parseOidArray(PQgetvalue(res, j, i_indkey),
5128                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5129                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5130                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5131                         contype = *(PQgetvalue(res, j, i_contype));
5132
5133                         if (contype == 'p' || contype == 'u' || contype == 'x')
5134                         {
5135                                 /*
5136                                  * If we found a constraint matching the index, create an
5137                                  * entry for it.
5138                                  *
5139                                  * In a pre-7.3 database, we take this path iff the index was
5140                                  * marked indisprimary.
5141                                  */
5142                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5143                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5144                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5145                                 AssignDumpId(&constrinfo[j].dobj);
5146                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5147                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5148                                 constrinfo[j].contable = tbinfo;
5149                                 constrinfo[j].condomain = NULL;
5150                                 constrinfo[j].contype = contype;
5151                                 if (contype == 'x')
5152                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5153                                 else
5154                                         constrinfo[j].condef = NULL;
5155                                 constrinfo[j].confrelid = InvalidOid;
5156                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5157                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5158                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5159                                 constrinfo[j].conislocal = true;
5160                                 constrinfo[j].separate = true;
5161
5162                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5163
5164                                 /* If pre-7.3 DB, better make sure table comes first */
5165                                 addObjectDependency(&constrinfo[j].dobj,
5166                                                                         tbinfo->dobj.dumpId);
5167                         }
5168                         else
5169                         {
5170                                 /* Plain secondary index */
5171                                 indxinfo[j].indexconstraint = 0;
5172                         }
5173                 }
5174
5175                 PQclear(res);
5176         }
5177
5178         destroyPQExpBuffer(query);
5179 }
5180
5181 /*
5182  * getConstraints
5183  *
5184  * Get info about constraints on dumpable tables.
5185  *
5186  * Currently handles foreign keys only.
5187  * Unique and primary key constraints are handled with indexes,
5188  * while check constraints are processed in getTableAttrs().
5189  */
5190 void
5191 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5192 {
5193         int                     i,
5194                                 j;
5195         ConstraintInfo *constrinfo;
5196         PQExpBuffer query;
5197         PGresult   *res;
5198         int                     i_contableoid,
5199                                 i_conoid,
5200                                 i_conname,
5201                                 i_confrelid,
5202                                 i_condef;
5203         int                     ntups;
5204
5205         /* pg_constraint was created in 7.3, so nothing to do if older */
5206         if (fout->remoteVersion < 70300)
5207                 return;
5208
5209         query = createPQExpBuffer();
5210
5211         for (i = 0; i < numTables; i++)
5212         {
5213                 TableInfo  *tbinfo = &tblinfo[i];
5214
5215                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5216                         continue;
5217
5218                 if (g_verbose)
5219                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
5220                                           tbinfo->dobj.name);
5221
5222                 /*
5223                  * select table schema to ensure constraint expr is qualified if
5224                  * needed
5225                  */
5226                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5227
5228                 resetPQExpBuffer(query);
5229                 appendPQExpBuffer(query,
5230                                                   "SELECT tableoid, oid, conname, confrelid, "
5231                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5232                                                   "FROM pg_catalog.pg_constraint "
5233                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5234                                                   "AND contype = 'f'",
5235                                                   tbinfo->dobj.catId.oid);
5236                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5237
5238                 ntups = PQntuples(res);
5239
5240                 i_contableoid = PQfnumber(res, "tableoid");
5241                 i_conoid = PQfnumber(res, "oid");
5242                 i_conname = PQfnumber(res, "conname");
5243                 i_confrelid = PQfnumber(res, "confrelid");
5244                 i_condef = PQfnumber(res, "condef");
5245
5246                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5247
5248                 for (j = 0; j < ntups; j++)
5249                 {
5250                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5251                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5252                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5253                         AssignDumpId(&constrinfo[j].dobj);
5254                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5255                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5256                         constrinfo[j].contable = tbinfo;
5257                         constrinfo[j].condomain = NULL;
5258                         constrinfo[j].contype = 'f';
5259                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5260                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5261                         constrinfo[j].conindex = 0;
5262                         constrinfo[j].condeferrable = false;
5263                         constrinfo[j].condeferred = false;
5264                         constrinfo[j].conislocal = true;
5265                         constrinfo[j].separate = true;
5266                 }
5267
5268                 PQclear(res);
5269         }
5270
5271         destroyPQExpBuffer(query);
5272 }
5273
5274 /*
5275  * getDomainConstraints
5276  *
5277  * Get info about constraints on a domain.
5278  */
5279 static void
5280 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5281 {
5282         int                     i;
5283         ConstraintInfo *constrinfo;
5284         PQExpBuffer query;
5285         PGresult   *res;
5286         int                     i_tableoid,
5287                                 i_oid,
5288                                 i_conname,
5289                                 i_consrc;
5290         int                     ntups;
5291
5292         /* pg_constraint was created in 7.3, so nothing to do if older */
5293         if (fout->remoteVersion < 70300)
5294                 return;
5295
5296         /*
5297          * select appropriate schema to ensure names in constraint are properly
5298          * qualified
5299          */
5300         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5301
5302         query = createPQExpBuffer();
5303
5304         if (fout->remoteVersion >= 90100)
5305                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5306                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5307                                                   "convalidated "
5308                                                   "FROM pg_catalog.pg_constraint "
5309                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5310                                                   "ORDER BY conname",
5311                                                   tyinfo->dobj.catId.oid);
5312
5313         else if (fout->remoteVersion >= 70400)
5314                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5315                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5316                                                   "true as convalidated "
5317                                                   "FROM pg_catalog.pg_constraint "
5318                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5319                                                   "ORDER BY conname",
5320                                                   tyinfo->dobj.catId.oid);
5321         else
5322                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5323                                                   "'CHECK (' || consrc || ')' AS consrc, "
5324                                                   "true as convalidated "
5325                                                   "FROM pg_catalog.pg_constraint "
5326                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5327                                                   "ORDER BY conname",
5328                                                   tyinfo->dobj.catId.oid);
5329
5330         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5331
5332         ntups = PQntuples(res);
5333
5334         i_tableoid = PQfnumber(res, "tableoid");
5335         i_oid = PQfnumber(res, "oid");
5336         i_conname = PQfnumber(res, "conname");
5337         i_consrc = PQfnumber(res, "consrc");
5338
5339         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5340
5341         tyinfo->nDomChecks = ntups;
5342         tyinfo->domChecks = constrinfo;
5343
5344         for (i = 0; i < ntups; i++)
5345         {
5346                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5347
5348                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5349                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5350                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5351                 AssignDumpId(&constrinfo[i].dobj);
5352                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5353                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5354                 constrinfo[i].contable = NULL;
5355                 constrinfo[i].condomain = tyinfo;
5356                 constrinfo[i].contype = 'c';
5357                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5358                 constrinfo[i].confrelid = InvalidOid;
5359                 constrinfo[i].conindex = 0;
5360                 constrinfo[i].condeferrable = false;
5361                 constrinfo[i].condeferred = false;
5362                 constrinfo[i].conislocal = true;
5363
5364                 constrinfo[i].separate = !validated;
5365
5366                 /*
5367                  * Make the domain depend on the constraint, ensuring it won't be
5368                  * output till any constraint dependencies are OK.      If the constraint
5369                  * has not been validated, it's going to be dumped after the domain
5370                  * anyway, so this doesn't matter.
5371                  */
5372                 if (validated)
5373                         addObjectDependency(&tyinfo->dobj,
5374                                                                 constrinfo[i].dobj.dumpId);
5375         }
5376
5377         PQclear(res);
5378
5379         destroyPQExpBuffer(query);
5380 }
5381
5382 /*
5383  * getRules
5384  *        get basic information about every rule in the system
5385  *
5386  * numRules is set to the number of rules read in
5387  */
5388 RuleInfo *
5389 getRules(Archive *fout, int *numRules)
5390 {
5391         PGresult   *res;
5392         int                     ntups;
5393         int                     i;
5394         PQExpBuffer query = createPQExpBuffer();
5395         RuleInfo   *ruleinfo;
5396         int                     i_tableoid;
5397         int                     i_oid;
5398         int                     i_rulename;
5399         int                     i_ruletable;
5400         int                     i_ev_type;
5401         int                     i_is_instead;
5402         int                     i_ev_enabled;
5403
5404         /* Make sure we are in proper schema */
5405         selectSourceSchema(fout, "pg_catalog");
5406
5407         if (fout->remoteVersion >= 80300)
5408         {
5409                 appendPQExpBuffer(query, "SELECT "
5410                                                   "tableoid, oid, rulename, "
5411                                                   "ev_class AS ruletable, ev_type, is_instead, "
5412                                                   "ev_enabled "
5413                                                   "FROM pg_rewrite "
5414                                                   "ORDER BY oid");
5415         }
5416         else if (fout->remoteVersion >= 70100)
5417         {
5418                 appendPQExpBuffer(query, "SELECT "
5419                                                   "tableoid, oid, rulename, "
5420                                                   "ev_class AS ruletable, ev_type, is_instead, "
5421                                                   "'O'::char AS ev_enabled "
5422                                                   "FROM pg_rewrite "
5423                                                   "ORDER BY oid");
5424         }
5425         else
5426         {
5427                 appendPQExpBuffer(query, "SELECT "
5428                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5429                                                   "oid, rulename, "
5430                                                   "ev_class AS ruletable, ev_type, is_instead, "
5431                                                   "'O'::char AS ev_enabled "
5432                                                   "FROM pg_rewrite "
5433                                                   "ORDER BY oid");
5434         }
5435
5436         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5437
5438         ntups = PQntuples(res);
5439
5440         *numRules = ntups;
5441
5442         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5443
5444         i_tableoid = PQfnumber(res, "tableoid");
5445         i_oid = PQfnumber(res, "oid");
5446         i_rulename = PQfnumber(res, "rulename");
5447         i_ruletable = PQfnumber(res, "ruletable");
5448         i_ev_type = PQfnumber(res, "ev_type");
5449         i_is_instead = PQfnumber(res, "is_instead");
5450         i_ev_enabled = PQfnumber(res, "ev_enabled");
5451
5452         for (i = 0; i < ntups; i++)
5453         {
5454                 Oid                     ruletableoid;
5455
5456                 ruleinfo[i].dobj.objType = DO_RULE;
5457                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5458                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5459                 AssignDumpId(&ruleinfo[i].dobj);
5460                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5461                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5462                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5463                 if (ruleinfo[i].ruletable == NULL)
5464                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5465                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5466                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5467                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5468                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5469                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5470                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5471                 if (ruleinfo[i].ruletable)
5472                 {
5473                         /*
5474                          * If the table is a view or materialized view, force its ON
5475                          * SELECT rule to be sorted before the view itself --- this
5476                          * ensures that any dependencies for the rule affect the table's
5477                          * positioning. Other rules are forced to appear after their
5478                          * table.
5479                          */
5480                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5481                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5482                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5483                         {
5484                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5485                                                                         ruleinfo[i].dobj.dumpId);
5486                                 /* We'll merge the rule into CREATE VIEW, if possible */
5487                                 ruleinfo[i].separate = false;
5488                         }
5489                         else
5490                         {
5491                                 addObjectDependency(&ruleinfo[i].dobj,
5492                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5493                                 ruleinfo[i].separate = true;
5494                         }
5495                 }
5496                 else
5497                         ruleinfo[i].separate = true;
5498
5499                 /*
5500                  * If we're forced to break a dependency loop by dumping a view as a
5501                  * table and separate _RETURN rule, we'll move the view's reloptions
5502                  * to the rule.  (This is necessary because tables and views have
5503                  * different valid reloptions, so we can't apply the options until the
5504                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5505                  * NULL.
5506                  */
5507                 ruleinfo[i].reloptions = NULL;
5508         }
5509
5510         PQclear(res);
5511
5512         destroyPQExpBuffer(query);
5513
5514         return ruleinfo;
5515 }
5516
5517 /*
5518  * getTriggers
5519  *        get information about every trigger on a dumpable table
5520  *
5521  * Note: trigger data is not returned directly to the caller, but it
5522  * does get entered into the DumpableObject tables.
5523  */
5524 void
5525 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5526 {
5527         int                     i,
5528                                 j;
5529         PQExpBuffer query = createPQExpBuffer();
5530         PGresult   *res;
5531         TriggerInfo *tginfo;
5532         int                     i_tableoid,
5533                                 i_oid,
5534                                 i_tgname,
5535                                 i_tgfname,
5536                                 i_tgtype,
5537                                 i_tgnargs,
5538                                 i_tgargs,
5539                                 i_tgisconstraint,
5540                                 i_tgconstrname,
5541                                 i_tgconstrrelid,
5542                                 i_tgconstrrelname,
5543                                 i_tgenabled,
5544                                 i_tgdeferrable,
5545                                 i_tginitdeferred,
5546                                 i_tgdef;
5547         int                     ntups;
5548
5549         for (i = 0; i < numTables; i++)
5550         {
5551                 TableInfo  *tbinfo = &tblinfo[i];
5552
5553                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5554                         continue;
5555
5556                 if (g_verbose)
5557                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5558                                           tbinfo->dobj.name);
5559
5560                 /*
5561                  * select table schema to ensure regproc name is qualified if needed
5562                  */
5563                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5564
5565                 resetPQExpBuffer(query);
5566                 if (fout->remoteVersion >= 90000)
5567                 {
5568                         /*
5569                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5570                          * could result in non-forward-compatible dumps of WHEN clauses
5571                          * due to under-parenthesization.
5572                          */
5573                         appendPQExpBuffer(query,
5574                                                           "SELECT tgname, "
5575                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5576                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5577                                                           "tgenabled, tableoid, oid "
5578                                                           "FROM pg_catalog.pg_trigger t "
5579                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5580                                                           "AND NOT tgisinternal",
5581                                                           tbinfo->dobj.catId.oid);
5582                 }
5583                 else if (fout->remoteVersion >= 80300)
5584                 {
5585                         /*
5586                          * We ignore triggers that are tied to a foreign-key constraint
5587                          */
5588                         appendPQExpBuffer(query,
5589                                                           "SELECT tgname, "
5590                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5591                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5592                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5593                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5594                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5595                                                           "FROM pg_catalog.pg_trigger t "
5596                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5597                                                           "AND tgconstraint = 0",
5598                                                           tbinfo->dobj.catId.oid);
5599                 }
5600                 else if (fout->remoteVersion >= 70300)
5601                 {
5602                         /*
5603                          * We ignore triggers that are tied to a foreign-key constraint,
5604                          * but in these versions we have to grovel through pg_constraint
5605                          * to find out
5606                          */
5607                         appendPQExpBuffer(query,
5608                                                           "SELECT tgname, "
5609                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5610                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5611                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5612                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5613                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5614                                                           "FROM pg_catalog.pg_trigger t "
5615                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5616                                                           "AND (NOT tgisconstraint "
5617                                                           " OR NOT EXISTS"
5618                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5619                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5620                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5621                                                           tbinfo->dobj.catId.oid);
5622                 }
5623                 else if (fout->remoteVersion >= 70100)
5624                 {
5625                         appendPQExpBuffer(query,
5626                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5627                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5628                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5629                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5630                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5631                                                           "             AS tgconstrrelname "
5632                                                           "FROM pg_trigger "
5633                                                           "WHERE tgrelid = '%u'::oid",
5634                                                           tbinfo->dobj.catId.oid);
5635                 }
5636                 else
5637                 {
5638                         appendPQExpBuffer(query,
5639                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5640                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5641                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5642                                                           "tgconstrrelid, tginitdeferred, "
5643                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5644                                                           "oid, "
5645                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5646                                                           "             AS tgconstrrelname "
5647                                                           "FROM pg_trigger "
5648                                                           "WHERE tgrelid = '%u'::oid",
5649                                                           tbinfo->dobj.catId.oid);
5650                 }
5651                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5652
5653                 ntups = PQntuples(res);
5654
5655                 i_tableoid = PQfnumber(res, "tableoid");
5656                 i_oid = PQfnumber(res, "oid");
5657                 i_tgname = PQfnumber(res, "tgname");
5658                 i_tgfname = PQfnumber(res, "tgfname");
5659                 i_tgtype = PQfnumber(res, "tgtype");
5660                 i_tgnargs = PQfnumber(res, "tgnargs");
5661                 i_tgargs = PQfnumber(res, "tgargs");
5662                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5663                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5664                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5665                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5666                 i_tgenabled = PQfnumber(res, "tgenabled");
5667                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5668                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5669                 i_tgdef = PQfnumber(res, "tgdef");
5670
5671                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5672
5673                 for (j = 0; j < ntups; j++)
5674                 {
5675                         tginfo[j].dobj.objType = DO_TRIGGER;
5676                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5677                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5678                         AssignDumpId(&tginfo[j].dobj);
5679                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5680                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5681                         tginfo[j].tgtable = tbinfo;
5682                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5683                         if (i_tgdef >= 0)
5684                         {
5685                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5686
5687                                 /* remaining fields are not valid if we have tgdef */
5688                                 tginfo[j].tgfname = NULL;
5689                                 tginfo[j].tgtype = 0;
5690                                 tginfo[j].tgnargs = 0;
5691                                 tginfo[j].tgargs = NULL;
5692                                 tginfo[j].tgisconstraint = false;
5693                                 tginfo[j].tgdeferrable = false;
5694                                 tginfo[j].tginitdeferred = false;
5695                                 tginfo[j].tgconstrname = NULL;
5696                                 tginfo[j].tgconstrrelid = InvalidOid;
5697                                 tginfo[j].tgconstrrelname = NULL;
5698                         }
5699                         else
5700                         {
5701                                 tginfo[j].tgdef = NULL;
5702
5703                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5704                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5705                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5706                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5707                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5708                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5709                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5710
5711                                 if (tginfo[j].tgisconstraint)
5712                                 {
5713                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5714                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5715                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5716                                         {
5717                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5718                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5719                                                                                   tginfo[j].dobj.name,
5720                                                                                   tbinfo->dobj.name,
5721                                                                                   tginfo[j].tgconstrrelid);
5722                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5723                                         }
5724                                         else
5725                                                 tginfo[j].tgconstrrelname = NULL;
5726                                 }
5727                                 else
5728                                 {
5729                                         tginfo[j].tgconstrname = NULL;
5730                                         tginfo[j].tgconstrrelid = InvalidOid;
5731                                         tginfo[j].tgconstrrelname = NULL;
5732                                 }
5733                         }
5734                 }
5735
5736                 PQclear(res);
5737         }
5738
5739         destroyPQExpBuffer(query);
5740 }
5741
5742 /*
5743  * getEventTriggers
5744  *        get information about event triggers
5745  */
5746 EventTriggerInfo *
5747 getEventTriggers(Archive *fout, int *numEventTriggers)
5748 {
5749         int                     i;
5750         PQExpBuffer query = createPQExpBuffer();
5751         PGresult   *res;
5752         EventTriggerInfo *evtinfo;
5753         int                     i_tableoid,
5754                                 i_oid,
5755                                 i_evtname,
5756                                 i_evtevent,
5757                                 i_evtowner,
5758                                 i_evttags,
5759                                 i_evtfname,
5760                                 i_evtenabled;
5761         int                     ntups;
5762
5763         /* Before 9.3, there are no event triggers */
5764         if (fout->remoteVersion < 90300)
5765         {
5766                 *numEventTriggers = 0;
5767                 return NULL;
5768         }
5769
5770         /* Make sure we are in proper schema */
5771         selectSourceSchema(fout, "pg_catalog");
5772
5773         appendPQExpBuffer(query,
5774                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5775                                           "evtevent, (%s evtowner) AS evtowner, "
5776                                           "array_to_string(array("
5777                                           "select quote_literal(x) "
5778                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5779                                           "e.evtfoid::regproc as evtfname "
5780                                           "FROM pg_event_trigger e "
5781                                           "ORDER BY e.oid",
5782                                           username_subquery);
5783
5784         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5785
5786         ntups = PQntuples(res);
5787
5788         *numEventTriggers = ntups;
5789
5790         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5791
5792         i_tableoid = PQfnumber(res, "tableoid");
5793         i_oid = PQfnumber(res, "oid");
5794         i_evtname = PQfnumber(res, "evtname");
5795         i_evtevent = PQfnumber(res, "evtevent");
5796         i_evtowner = PQfnumber(res, "evtowner");
5797         i_evttags = PQfnumber(res, "evttags");
5798         i_evtfname = PQfnumber(res, "evtfname");
5799         i_evtenabled = PQfnumber(res, "evtenabled");
5800
5801         for (i = 0; i < ntups; i++)
5802         {
5803                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5804                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5805                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5806                 AssignDumpId(&evtinfo[i].dobj);
5807                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5808                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5809                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5810                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5811                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5812                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5813                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5814         }
5815
5816         PQclear(res);
5817
5818         destroyPQExpBuffer(query);
5819
5820         return evtinfo;
5821 }
5822
5823 /*
5824  * getProcLangs
5825  *        get basic information about every procedural language in the system
5826  *
5827  * numProcLangs is set to the number of langs read in
5828  *
5829  * NB: this must run after getFuncs() because we assume we can do
5830  * findFuncByOid().
5831  */
5832 ProcLangInfo *
5833 getProcLangs(Archive *fout, int *numProcLangs)
5834 {
5835         PGresult   *res;
5836         int                     ntups;
5837         int                     i;
5838         PQExpBuffer query = createPQExpBuffer();
5839         ProcLangInfo *planginfo;
5840         int                     i_tableoid;
5841         int                     i_oid;
5842         int                     i_lanname;
5843         int                     i_lanpltrusted;
5844         int                     i_lanplcallfoid;
5845         int                     i_laninline;
5846         int                     i_lanvalidator;
5847         int                     i_lanacl;
5848         int                     i_lanowner;
5849
5850         /* Make sure we are in proper schema */
5851         selectSourceSchema(fout, "pg_catalog");
5852
5853         if (fout->remoteVersion >= 90000)
5854         {
5855                 /* pg_language has a laninline column */
5856                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5857                                                   "lanname, lanpltrusted, lanplcallfoid, "
5858                                                   "laninline, lanvalidator,  lanacl, "
5859                                                   "(%s lanowner) AS lanowner "
5860                                                   "FROM pg_language "
5861                                                   "WHERE lanispl "
5862                                                   "ORDER BY oid",
5863                                                   username_subquery);
5864         }
5865         else if (fout->remoteVersion >= 80300)
5866         {
5867                 /* pg_language has a lanowner column */
5868                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5869                                                   "lanname, lanpltrusted, lanplcallfoid, "
5870                                                   "lanvalidator,  lanacl, "
5871                                                   "(%s lanowner) AS lanowner "
5872                                                   "FROM pg_language "
5873                                                   "WHERE lanispl "
5874                                                   "ORDER BY oid",
5875                                                   username_subquery);
5876         }
5877         else if (fout->remoteVersion >= 80100)
5878         {
5879                 /* Languages are owned by the bootstrap superuser, OID 10 */
5880                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5881                                                   "(%s '10') AS lanowner "
5882                                                   "FROM pg_language "
5883                                                   "WHERE lanispl "
5884                                                   "ORDER BY oid",
5885                                                   username_subquery);
5886         }
5887         else if (fout->remoteVersion >= 70400)
5888         {
5889                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5890                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5891                                                   "(%s '1') AS lanowner "
5892                                                   "FROM pg_language "
5893                                                   "WHERE lanispl "
5894                                                   "ORDER BY oid",
5895                                                   username_subquery);
5896         }
5897         else if (fout->remoteVersion >= 70100)
5898         {
5899                 /* No clear notion of an owner at all before 7.4 ... */
5900                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5901                                                   "WHERE lanispl "
5902                                                   "ORDER BY oid");
5903         }
5904         else
5905         {
5906                 appendPQExpBuffer(query, "SELECT "
5907                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5908                                                   "oid, * FROM pg_language "
5909                                                   "WHERE lanispl "
5910                                                   "ORDER BY oid");
5911         }
5912
5913         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5914
5915         ntups = PQntuples(res);
5916
5917         *numProcLangs = ntups;
5918
5919         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5920
5921         i_tableoid = PQfnumber(res, "tableoid");
5922         i_oid = PQfnumber(res, "oid");
5923         i_lanname = PQfnumber(res, "lanname");
5924         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5925         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5926         /* these may fail and return -1: */
5927         i_laninline = PQfnumber(res, "laninline");
5928         i_lanvalidator = PQfnumber(res, "lanvalidator");
5929         i_lanacl = PQfnumber(res, "lanacl");
5930         i_lanowner = PQfnumber(res, "lanowner");
5931
5932         for (i = 0; i < ntups; i++)
5933         {
5934                 planginfo[i].dobj.objType = DO_PROCLANG;
5935                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5936                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5937                 AssignDumpId(&planginfo[i].dobj);
5938
5939                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5940                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5941                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5942                 if (i_laninline >= 0)
5943                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5944                 else
5945                         planginfo[i].laninline = InvalidOid;
5946                 if (i_lanvalidator >= 0)
5947                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5948                 else
5949                         planginfo[i].lanvalidator = InvalidOid;
5950                 if (i_lanacl >= 0)
5951                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5952                 else
5953                         planginfo[i].lanacl = pg_strdup("{=U}");
5954                 if (i_lanowner >= 0)
5955                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5956                 else
5957                         planginfo[i].lanowner = pg_strdup("");
5958
5959                 if (fout->remoteVersion < 70300)
5960                 {
5961                         /*
5962                          * We need to make a dependency to ensure the function will be
5963                          * dumped first.  (In 7.3 and later the regular dependency
5964                          * mechanism will handle this for us.)
5965                          */
5966                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5967
5968                         if (funcInfo)
5969                                 addObjectDependency(&planginfo[i].dobj,
5970                                                                         funcInfo->dobj.dumpId);
5971                 }
5972         }
5973
5974         PQclear(res);
5975
5976         destroyPQExpBuffer(query);
5977
5978         return planginfo;
5979 }
5980
5981 /*
5982  * getCasts
5983  *        get basic information about every cast in the system
5984  *
5985  * numCasts is set to the number of casts read in
5986  */
5987 CastInfo *
5988 getCasts(Archive *fout, int *numCasts)
5989 {
5990         PGresult   *res;
5991         int                     ntups;
5992         int                     i;
5993         PQExpBuffer query = createPQExpBuffer();
5994         CastInfo   *castinfo;
5995         int                     i_tableoid;
5996         int                     i_oid;
5997         int                     i_castsource;
5998         int                     i_casttarget;
5999         int                     i_castfunc;
6000         int                     i_castcontext;
6001         int                     i_castmethod;
6002
6003         /* Make sure we are in proper schema */
6004         selectSourceSchema(fout, "pg_catalog");
6005
6006         if (fout->remoteVersion >= 80400)
6007         {
6008                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6009                                                   "castsource, casttarget, castfunc, castcontext, "
6010                                                   "castmethod "
6011                                                   "FROM pg_cast ORDER BY 3,4");
6012         }
6013         else if (fout->remoteVersion >= 70300)
6014         {
6015                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6016                                                   "castsource, casttarget, castfunc, castcontext, "
6017                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6018                                                   "FROM pg_cast ORDER BY 3,4");
6019         }
6020         else
6021         {
6022                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
6023                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
6024                                                   "p.oid AS castfunc, 'e' AS castcontext, "
6025                                                   "'f' AS castmethod "
6026                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
6027                                                   "WHERE p.pronargs = 1 AND "
6028                                                   "p.proargtypes[0] = t1.oid AND "
6029                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
6030                                                   "ORDER BY 3,4");
6031         }
6032
6033         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6034
6035         ntups = PQntuples(res);
6036
6037         *numCasts = ntups;
6038
6039         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6040
6041         i_tableoid = PQfnumber(res, "tableoid");
6042         i_oid = PQfnumber(res, "oid");
6043         i_castsource = PQfnumber(res, "castsource");
6044         i_casttarget = PQfnumber(res, "casttarget");
6045         i_castfunc = PQfnumber(res, "castfunc");
6046         i_castcontext = PQfnumber(res, "castcontext");
6047         i_castmethod = PQfnumber(res, "castmethod");
6048
6049         for (i = 0; i < ntups; i++)
6050         {
6051                 PQExpBufferData namebuf;
6052                 TypeInfo   *sTypeInfo;
6053                 TypeInfo   *tTypeInfo;
6054
6055                 castinfo[i].dobj.objType = DO_CAST;
6056                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6057                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6058                 AssignDumpId(&castinfo[i].dobj);
6059                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6060                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6061                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6062                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6063                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6064
6065                 /*
6066                  * Try to name cast as concatenation of typnames.  This is only used
6067                  * for purposes of sorting.  If we fail to find either type, the name
6068                  * will be an empty string.
6069                  */
6070                 initPQExpBuffer(&namebuf);
6071                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6072                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6073                 if (sTypeInfo && tTypeInfo)
6074                         appendPQExpBuffer(&namebuf, "%s %s",
6075                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6076                 castinfo[i].dobj.name = namebuf.data;
6077
6078                 if (OidIsValid(castinfo[i].castfunc))
6079                 {
6080                         /*
6081                          * We need to make a dependency to ensure the function will be
6082                          * dumped first.  (In 7.3 and later the regular dependency
6083                          * mechanism will handle this for us.)
6084                          */
6085                         FuncInfo   *funcInfo;
6086
6087                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6088                         if (funcInfo)
6089                                 addObjectDependency(&castinfo[i].dobj,
6090                                                                         funcInfo->dobj.dumpId);
6091                 }
6092         }
6093
6094         PQclear(res);
6095
6096         destroyPQExpBuffer(query);
6097
6098         return castinfo;
6099 }
6100
6101 /*
6102  * getTableAttrs -
6103  *        for each interesting table, read info about its attributes
6104  *        (names, types, default values, CHECK constraints, etc)
6105  *
6106  * This is implemented in a very inefficient way right now, looping
6107  * through the tblinfo and doing a join per table to find the attrs and their
6108  * types.  However, because we want type names and so forth to be named
6109  * relative to the schema of each table, we couldn't do it in just one
6110  * query.  (Maybe one query per schema?)
6111  *
6112  *      modifies tblinfo
6113  */
6114 void
6115 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
6116 {
6117         int                     i,
6118                                 j;
6119         PQExpBuffer q = createPQExpBuffer();
6120         int                     i_attnum;
6121         int                     i_attname;
6122         int                     i_atttypname;
6123         int                     i_atttypmod;
6124         int                     i_attstattarget;
6125         int                     i_attstorage;
6126         int                     i_typstorage;
6127         int                     i_attnotnull;
6128         int                     i_atthasdef;
6129         int                     i_attisdropped;
6130         int                     i_attlen;
6131         int                     i_attalign;
6132         int                     i_attislocal;
6133         int                     i_attoptions;
6134         int                     i_attcollation;
6135         int                     i_attfdwoptions;
6136         PGresult   *res;
6137         int                     ntups;
6138         bool            hasdefaults;
6139
6140         for (i = 0; i < numTables; i++)
6141         {
6142                 TableInfo  *tbinfo = &tblinfo[i];
6143
6144                 /* Don't bother to collect info for sequences */
6145                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6146                         continue;
6147
6148                 /* Don't bother with uninteresting tables, either */
6149                 if (!tbinfo->interesting)
6150                         continue;
6151
6152                 /*
6153                  * Make sure we are in proper schema for this table; this allows
6154                  * correct retrieval of formatted type names and default exprs
6155                  */
6156                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6157
6158                 /* find all the user attributes and their types */
6159
6160                 /*
6161                  * we must read the attribute names in attribute number order! because
6162                  * we will use the attnum to index into the attnames array later.  We
6163                  * actually ask to order by "attrelid, attnum" because (at least up to
6164                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6165                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6166                  */
6167                 if (g_verbose)
6168                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
6169                                           tbinfo->dobj.name);
6170
6171                 resetPQExpBuffer(q);
6172
6173                 if (fout->remoteVersion >= 90200)
6174                 {
6175                         /*
6176                          * attfdwoptions is new in 9.2.
6177                          */
6178                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6179                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6180                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6181                                                           "a.attlen, a.attalign, a.attislocal, "
6182                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6183                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6184                                                           "CASE WHEN a.attcollation <> t.typcollation "
6185                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6186                                                           "pg_catalog.array_to_string(ARRAY("
6187                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6188                                                           "' ' || pg_catalog.quote_literal(option_value) "
6189                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6190                                                           "ORDER BY option_name"
6191                                                           "), E',\n    ') AS attfdwoptions "
6192                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6193                                                           "ON a.atttypid = t.oid "
6194                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6195                                                           "AND a.attnum > 0::pg_catalog.int2 "
6196                                                           "ORDER BY a.attrelid, a.attnum",
6197                                                           tbinfo->dobj.catId.oid);
6198                 }
6199                 else if (fout->remoteVersion >= 90100)
6200                 {
6201                         /*
6202                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6203                          * clauses for attributes whose collation is different from their
6204                          * type's default, we use a CASE here to suppress uninteresting
6205                          * attcollations cheaply.
6206                          */
6207                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6208                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6209                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6210                                                           "a.attlen, a.attalign, a.attislocal, "
6211                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6212                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6213                                                           "CASE WHEN a.attcollation <> t.typcollation "
6214                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6215                                                           "NULL AS attfdwoptions "
6216                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6217                                                           "ON a.atttypid = t.oid "
6218                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6219                                                           "AND a.attnum > 0::pg_catalog.int2 "
6220                                                           "ORDER BY a.attrelid, a.attnum",
6221                                                           tbinfo->dobj.catId.oid);
6222                 }
6223                 else if (fout->remoteVersion >= 90000)
6224                 {
6225                         /* attoptions is new in 9.0 */
6226                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6227                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6228                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6229                                                           "a.attlen, a.attalign, a.attislocal, "
6230                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6231                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6232                                                           "0 AS attcollation, "
6233                                                           "NULL AS attfdwoptions "
6234                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6235                                                           "ON a.atttypid = t.oid "
6236                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6237                                                           "AND a.attnum > 0::pg_catalog.int2 "
6238                                                           "ORDER BY a.attrelid, a.attnum",
6239                                                           tbinfo->dobj.catId.oid);
6240                 }
6241                 else if (fout->remoteVersion >= 70300)
6242                 {
6243                         /* need left join here to not fail on dropped columns ... */
6244                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6245                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6246                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6247                                                           "a.attlen, a.attalign, a.attislocal, "
6248                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6249                                                           "'' AS attoptions, 0 AS attcollation, "
6250                                                           "NULL AS attfdwoptions "
6251                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6252                                                           "ON a.atttypid = t.oid "
6253                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6254                                                           "AND a.attnum > 0::pg_catalog.int2 "
6255                                                           "ORDER BY a.attrelid, a.attnum",
6256                                                           tbinfo->dobj.catId.oid);
6257                 }
6258                 else if (fout->remoteVersion >= 70100)
6259                 {
6260                         /*
6261                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6262                          * we don't dump it because we can't tell whether it's been
6263                          * explicitly set or was just a default.
6264                          *
6265                          * attislocal doesn't exist before 7.3, either; in older databases
6266                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6267                          */
6268                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6269                                                           "-1 AS attstattarget, a.attstorage, "
6270                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6271                                                           "false AS attisdropped, a.attlen, "
6272                                                           "a.attalign, true AS attislocal, "
6273                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6274                                                           "'' AS attoptions, 0 AS attcollation, "
6275                                                           "NULL AS attfdwoptions "
6276                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6277                                                           "ON a.atttypid = t.oid "
6278                                                           "WHERE a.attrelid = '%u'::oid "
6279                                                           "AND a.attnum > 0::int2 "
6280                                                           "ORDER BY a.attrelid, a.attnum",
6281                                                           tbinfo->dobj.catId.oid);
6282                 }
6283                 else
6284                 {
6285                         /* format_type not available before 7.1 */
6286                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6287                                                           "-1 AS attstattarget, "
6288                                                           "attstorage, attstorage AS typstorage, "
6289                                                           "attnotnull, atthasdef, false AS attisdropped, "
6290                                                           "attlen, attalign, "
6291                                                           "true AS attislocal, "
6292                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6293                                                           "'' AS attoptions, 0 AS attcollation, "
6294                                                           "NULL AS attfdwoptions "
6295                                                           "FROM pg_attribute a "
6296                                                           "WHERE attrelid = '%u'::oid "
6297                                                           "AND attnum > 0::int2 "
6298                                                           "ORDER BY attrelid, attnum",
6299                                                           tbinfo->dobj.catId.oid);
6300                 }
6301
6302                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6303
6304                 ntups = PQntuples(res);
6305
6306                 i_attnum = PQfnumber(res, "attnum");
6307                 i_attname = PQfnumber(res, "attname");
6308                 i_atttypname = PQfnumber(res, "atttypname");
6309                 i_atttypmod = PQfnumber(res, "atttypmod");
6310                 i_attstattarget = PQfnumber(res, "attstattarget");
6311                 i_attstorage = PQfnumber(res, "attstorage");
6312                 i_typstorage = PQfnumber(res, "typstorage");
6313                 i_attnotnull = PQfnumber(res, "attnotnull");
6314                 i_atthasdef = PQfnumber(res, "atthasdef");
6315                 i_attisdropped = PQfnumber(res, "attisdropped");
6316                 i_attlen = PQfnumber(res, "attlen");
6317                 i_attalign = PQfnumber(res, "attalign");
6318                 i_attislocal = PQfnumber(res, "attislocal");
6319                 i_attoptions = PQfnumber(res, "attoptions");
6320                 i_attcollation = PQfnumber(res, "attcollation");
6321                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6322
6323                 tbinfo->numatts = ntups;
6324                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6325                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6326                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6327                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6328                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6329                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6330                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6331                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6332                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6333                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6334                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6335                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6336                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6337                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6338                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6339                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6340                 hasdefaults = false;
6341
6342                 for (j = 0; j < ntups; j++)
6343                 {
6344                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6345                                 exit_horribly(NULL,
6346                                                           "invalid column numbering in table \"%s\"\n",
6347                                                           tbinfo->dobj.name);
6348                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6349                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6350                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6351                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6352                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6353                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6354                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6355                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6356                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6357                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6358                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6359                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6360                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6361                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6362                         tbinfo->attrdefs[j] = NULL; /* fix below */
6363                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6364                                 hasdefaults = true;
6365                         /* these flags will be set in flagInhAttrs() */
6366                         tbinfo->inhNotNull[j] = false;
6367                 }
6368
6369                 PQclear(res);
6370
6371                 /*
6372                  * Get info about column defaults
6373                  */
6374                 if (hasdefaults)
6375                 {
6376                         AttrDefInfo *attrdefs;
6377                         int                     numDefaults;
6378
6379                         if (g_verbose)
6380                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
6381                                                   tbinfo->dobj.name);
6382
6383                         resetPQExpBuffer(q);
6384                         if (fout->remoteVersion >= 70300)
6385                         {
6386                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6387                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6388                                                                   "FROM pg_catalog.pg_attrdef "
6389                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6390                                                                   tbinfo->dobj.catId.oid);
6391                         }
6392                         else if (fout->remoteVersion >= 70200)
6393                         {
6394                                 /* 7.2 did not have OIDs in pg_attrdef */
6395                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6396                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6397                                                                   "FROM pg_attrdef "
6398                                                                   "WHERE adrelid = '%u'::oid",
6399                                                                   tbinfo->dobj.catId.oid);
6400                         }
6401                         else if (fout->remoteVersion >= 70100)
6402                         {
6403                                 /* no pg_get_expr, so must rely on adsrc */
6404                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6405                                                                   "FROM pg_attrdef "
6406                                                                   "WHERE adrelid = '%u'::oid",
6407                                                                   tbinfo->dobj.catId.oid);
6408                         }
6409                         else
6410                         {
6411                                 /* no pg_get_expr, no tableoid either */
6412                                 appendPQExpBuffer(q, "SELECT "
6413                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6414                                                                   "oid, adnum, adsrc "
6415                                                                   "FROM pg_attrdef "
6416                                                                   "WHERE adrelid = '%u'::oid",
6417                                                                   tbinfo->dobj.catId.oid);
6418                         }
6419                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6420
6421                         numDefaults = PQntuples(res);
6422                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6423
6424                         for (j = 0; j < numDefaults; j++)
6425                         {
6426                                 int                     adnum;
6427
6428                                 adnum = atoi(PQgetvalue(res, j, 2));
6429
6430                                 if (adnum <= 0 || adnum > ntups)
6431                                         exit_horribly(NULL,
6432                                                                   "invalid adnum value %d for table \"%s\"\n",
6433                                                                   adnum, tbinfo->dobj.name);
6434
6435                                 /*
6436                                  * dropped columns shouldn't have defaults, but just in case,
6437                                  * ignore 'em
6438                                  */
6439                                 if (tbinfo->attisdropped[adnum - 1])
6440                                         continue;
6441
6442                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6443                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6444                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6445                                 AssignDumpId(&attrdefs[j].dobj);
6446                                 attrdefs[j].adtable = tbinfo;
6447                                 attrdefs[j].adnum = adnum;
6448                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6449
6450                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6451                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6452
6453                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6454
6455                                 /*
6456                                  * Defaults on a VIEW must always be dumped as separate ALTER
6457                                  * TABLE commands.      Defaults on regular tables are dumped as
6458                                  * part of the CREATE TABLE if possible, which it won't be if
6459                                  * the column is not going to be emitted explicitly.
6460                                  */
6461                                 if (tbinfo->relkind == RELKIND_VIEW)
6462                                 {
6463                                         attrdefs[j].separate = true;
6464                                         /* needed in case pre-7.3 DB: */
6465                                         addObjectDependency(&attrdefs[j].dobj,
6466                                                                                 tbinfo->dobj.dumpId);
6467                                 }
6468                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6469                                 {
6470                                         /* column will be suppressed, print default separately */
6471                                         attrdefs[j].separate = true;
6472                                         /* needed in case pre-7.3 DB: */
6473                                         addObjectDependency(&attrdefs[j].dobj,
6474                                                                                 tbinfo->dobj.dumpId);
6475                                 }
6476                                 else
6477                                 {
6478                                         attrdefs[j].separate = false;
6479
6480                                         /*
6481                                          * Mark the default as needing to appear before the table,
6482                                          * so that any dependencies it has must be emitted before
6483                                          * the CREATE TABLE.  If this is not possible, we'll
6484                                          * change to "separate" mode while sorting dependencies.
6485                                          */
6486                                         addObjectDependency(&tbinfo->dobj,
6487                                                                                 attrdefs[j].dobj.dumpId);
6488                                 }
6489
6490                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6491                         }
6492                         PQclear(res);
6493                 }
6494
6495                 /*
6496                  * Get info about table CHECK constraints
6497                  */
6498                 if (tbinfo->ncheck > 0)
6499                 {
6500                         ConstraintInfo *constrs;
6501                         int                     numConstrs;
6502
6503                         if (g_verbose)
6504                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6505                                                   tbinfo->dobj.name);
6506
6507                         resetPQExpBuffer(q);
6508                         if (fout->remoteVersion >= 90200)
6509                         {
6510                                 /*
6511                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6512                                  * but it wasn't ever false for check constraints until 9.2).
6513                                  */
6514                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6515                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6516                                                                   "conislocal, convalidated "
6517                                                                   "FROM pg_catalog.pg_constraint "
6518                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6519                                                                   "   AND contype = 'c' "
6520                                                                   "ORDER BY conname",
6521                                                                   tbinfo->dobj.catId.oid);
6522                         }
6523                         else if (fout->remoteVersion >= 80400)
6524                         {
6525                                 /* conislocal is new in 8.4 */
6526                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6527                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6528                                                                   "conislocal, true AS convalidated "
6529                                                                   "FROM pg_catalog.pg_constraint "
6530                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6531                                                                   "   AND contype = 'c' "
6532                                                                   "ORDER BY conname",
6533                                                                   tbinfo->dobj.catId.oid);
6534                         }
6535                         else if (fout->remoteVersion >= 70400)
6536                         {
6537                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6538                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6539                                                                   "true AS conislocal, true AS convalidated "
6540                                                                   "FROM pg_catalog.pg_constraint "
6541                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6542                                                                   "   AND contype = 'c' "
6543                                                                   "ORDER BY conname",
6544                                                                   tbinfo->dobj.catId.oid);
6545                         }
6546                         else if (fout->remoteVersion >= 70300)
6547                         {
6548                                 /* no pg_get_constraintdef, must use consrc */
6549                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6550                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6551                                                                   "true AS conislocal, true AS convalidated "
6552                                                                   "FROM pg_catalog.pg_constraint "
6553                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6554                                                                   "   AND contype = 'c' "
6555                                                                   "ORDER BY conname",
6556                                                                   tbinfo->dobj.catId.oid);
6557                         }
6558                         else if (fout->remoteVersion >= 70200)
6559                         {
6560                                 /* 7.2 did not have OIDs in pg_relcheck */
6561                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6562                                                                   "rcname AS conname, "
6563                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6564                                                                   "true AS conislocal, true AS convalidated "
6565                                                                   "FROM pg_relcheck "
6566                                                                   "WHERE rcrelid = '%u'::oid "
6567                                                                   "ORDER BY rcname",
6568                                                                   tbinfo->dobj.catId.oid);
6569                         }
6570                         else if (fout->remoteVersion >= 70100)
6571                         {
6572                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6573                                                                   "rcname AS conname, "
6574                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6575                                                                   "true AS conislocal, true AS convalidated "
6576                                                                   "FROM pg_relcheck "
6577                                                                   "WHERE rcrelid = '%u'::oid "
6578                                                                   "ORDER BY rcname",
6579                                                                   tbinfo->dobj.catId.oid);
6580                         }
6581                         else
6582                         {
6583                                 /* no tableoid in 7.0 */
6584                                 appendPQExpBuffer(q, "SELECT "
6585                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6586                                                                   "oid, rcname AS conname, "
6587                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6588                                                                   "true AS conislocal, true AS convalidated "
6589                                                                   "FROM pg_relcheck "
6590                                                                   "WHERE rcrelid = '%u'::oid "
6591                                                                   "ORDER BY rcname",
6592                                                                   tbinfo->dobj.catId.oid);
6593                         }
6594                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6595
6596                         numConstrs = PQntuples(res);
6597                         if (numConstrs != tbinfo->ncheck)
6598                         {
6599                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6600                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6601                                                                                  tbinfo->ncheck),
6602                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6603                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6604                                 exit_nicely(1);
6605                         }
6606
6607                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6608                         tbinfo->checkexprs = constrs;
6609
6610                         for (j = 0; j < numConstrs; j++)
6611                         {
6612                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6613
6614                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6615                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6616                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6617                                 AssignDumpId(&constrs[j].dobj);
6618                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6619                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6620                                 constrs[j].contable = tbinfo;
6621                                 constrs[j].condomain = NULL;
6622                                 constrs[j].contype = 'c';
6623                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6624                                 constrs[j].confrelid = InvalidOid;
6625                                 constrs[j].conindex = 0;
6626                                 constrs[j].condeferrable = false;
6627                                 constrs[j].condeferred = false;
6628                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6629
6630                                 /*
6631                                  * An unvalidated constraint needs to be dumped separately, so
6632                                  * that potentially-violating existing data is loaded before
6633                                  * the constraint.
6634                                  */
6635                                 constrs[j].separate = !validated;
6636
6637                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6638
6639                                 /*
6640                                  * Mark the constraint as needing to appear before the table
6641                                  * --- this is so that any other dependencies of the
6642                                  * constraint will be emitted before we try to create the
6643                                  * table.  If the constraint is to be dumped separately, it
6644                                  * will be dumped after data is loaded anyway, so don't do it.
6645                                  * (There's an automatic dependency in the opposite direction
6646                                  * anyway, so don't need to add one manually here.)
6647                                  */
6648                                 if (!constrs[j].separate)
6649                                         addObjectDependency(&tbinfo->dobj,
6650                                                                                 constrs[j].dobj.dumpId);
6651
6652                                 /*
6653                                  * If the constraint is inherited, this will be detected later
6654                                  * (in pre-8.4 databases).      We also detect later if the
6655                                  * constraint must be split out from the table definition.
6656                                  */
6657                         }
6658                         PQclear(res);
6659                 }
6660         }
6661
6662         destroyPQExpBuffer(q);
6663 }
6664
6665 /*
6666  * Test whether a column should be printed as part of table's CREATE TABLE.
6667  * Column number is zero-based.
6668  *
6669  * Normally this is always true, but it's false for dropped columns, as well
6670  * as those that were inherited without any local definition.  (If we print
6671  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6672  * However, in binary_upgrade mode, we must print all such columns anyway and
6673  * fix the attislocal/attisdropped state later, so as to keep control of the
6674  * physical column order.
6675  *
6676  * This function exists because there are scattered nonobvious places that
6677  * must be kept in sync with this decision.
6678  */
6679 bool
6680 shouldPrintColumn(TableInfo *tbinfo, int colno)
6681 {
6682         if (binary_upgrade)
6683                 return true;
6684         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6685 }
6686
6687
6688 /*
6689  * getTSParsers:
6690  *        read all text search parsers in the system catalogs and return them
6691  *        in the TSParserInfo* structure
6692  *
6693  *      numTSParsers is set to the number of parsers read in
6694  */
6695 TSParserInfo *
6696 getTSParsers(Archive *fout, int *numTSParsers)
6697 {
6698         PGresult   *res;
6699         int                     ntups;
6700         int                     i;
6701         PQExpBuffer query;
6702         TSParserInfo *prsinfo;
6703         int                     i_tableoid;
6704         int                     i_oid;
6705         int                     i_prsname;
6706         int                     i_prsnamespace;
6707         int                     i_prsstart;
6708         int                     i_prstoken;
6709         int                     i_prsend;
6710         int                     i_prsheadline;
6711         int                     i_prslextype;
6712
6713         /* Before 8.3, there is no built-in text search support */
6714         if (fout->remoteVersion < 80300)
6715         {
6716                 *numTSParsers = 0;
6717                 return NULL;
6718         }
6719
6720         query = createPQExpBuffer();
6721
6722         /*
6723          * find all text search objects, including builtin ones; we filter out
6724          * system-defined objects at dump-out time.
6725          */
6726
6727         /* Make sure we are in proper schema */
6728         selectSourceSchema(fout, "pg_catalog");
6729
6730         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6731                                           "prsstart::oid, prstoken::oid, "
6732                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6733                                           "FROM pg_ts_parser");
6734
6735         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6736
6737         ntups = PQntuples(res);
6738         *numTSParsers = ntups;
6739
6740         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6741
6742         i_tableoid = PQfnumber(res, "tableoid");
6743         i_oid = PQfnumber(res, "oid");
6744         i_prsname = PQfnumber(res, "prsname");
6745         i_prsnamespace = PQfnumber(res, "prsnamespace");
6746         i_prsstart = PQfnumber(res, "prsstart");
6747         i_prstoken = PQfnumber(res, "prstoken");
6748         i_prsend = PQfnumber(res, "prsend");
6749         i_prsheadline = PQfnumber(res, "prsheadline");
6750         i_prslextype = PQfnumber(res, "prslextype");
6751
6752         for (i = 0; i < ntups; i++)
6753         {
6754                 prsinfo[i].dobj.objType = DO_TSPARSER;
6755                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6756                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6757                 AssignDumpId(&prsinfo[i].dobj);
6758                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6759                 prsinfo[i].dobj.namespace =
6760                         findNamespace(fout,
6761                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6762                                                   prsinfo[i].dobj.catId.oid);
6763                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6764                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6765                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6766                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6767                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6768
6769                 /* Decide whether we want to dump it */
6770                 selectDumpableObject(&(prsinfo[i].dobj));
6771         }
6772
6773         PQclear(res);
6774
6775         destroyPQExpBuffer(query);
6776
6777         return prsinfo;
6778 }
6779
6780 /*
6781  * getTSDictionaries:
6782  *        read all text search dictionaries in the system catalogs and return them
6783  *        in the TSDictInfo* structure
6784  *
6785  *      numTSDicts is set to the number of dictionaries read in
6786  */
6787 TSDictInfo *
6788 getTSDictionaries(Archive *fout, int *numTSDicts)
6789 {
6790         PGresult   *res;
6791         int                     ntups;
6792         int                     i;
6793         PQExpBuffer query;
6794         TSDictInfo *dictinfo;
6795         int                     i_tableoid;
6796         int                     i_oid;
6797         int                     i_dictname;
6798         int                     i_dictnamespace;
6799         int                     i_rolname;
6800         int                     i_dicttemplate;
6801         int                     i_dictinitoption;
6802
6803         /* Before 8.3, there is no built-in text search support */
6804         if (fout->remoteVersion < 80300)
6805         {
6806                 *numTSDicts = 0;
6807                 return NULL;
6808         }
6809
6810         query = createPQExpBuffer();
6811
6812         /* Make sure we are in proper schema */
6813         selectSourceSchema(fout, "pg_catalog");
6814
6815         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6816                                           "dictnamespace, (%s dictowner) AS rolname, "
6817                                           "dicttemplate, dictinitoption "
6818                                           "FROM pg_ts_dict",
6819                                           username_subquery);
6820
6821         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6822
6823         ntups = PQntuples(res);
6824         *numTSDicts = ntups;
6825
6826         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6827
6828         i_tableoid = PQfnumber(res, "tableoid");
6829         i_oid = PQfnumber(res, "oid");
6830         i_dictname = PQfnumber(res, "dictname");
6831         i_dictnamespace = PQfnumber(res, "dictnamespace");
6832         i_rolname = PQfnumber(res, "rolname");
6833         i_dictinitoption = PQfnumber(res, "dictinitoption");
6834         i_dicttemplate = PQfnumber(res, "dicttemplate");
6835
6836         for (i = 0; i < ntups; i++)
6837         {
6838                 dictinfo[i].dobj.objType = DO_TSDICT;
6839                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6840                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6841                 AssignDumpId(&dictinfo[i].dobj);
6842                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6843                 dictinfo[i].dobj.namespace =
6844                         findNamespace(fout,
6845                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6846                                                   dictinfo[i].dobj.catId.oid);
6847                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6848                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6849                 if (PQgetisnull(res, i, i_dictinitoption))
6850                         dictinfo[i].dictinitoption = NULL;
6851                 else
6852                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6853
6854                 /* Decide whether we want to dump it */
6855                 selectDumpableObject(&(dictinfo[i].dobj));
6856         }
6857
6858         PQclear(res);
6859
6860         destroyPQExpBuffer(query);
6861
6862         return dictinfo;
6863 }
6864
6865 /*
6866  * getTSTemplates:
6867  *        read all text search templates in the system catalogs and return them
6868  *        in the TSTemplateInfo* structure
6869  *
6870  *      numTSTemplates is set to the number of templates read in
6871  */
6872 TSTemplateInfo *
6873 getTSTemplates(Archive *fout, int *numTSTemplates)
6874 {
6875         PGresult   *res;
6876         int                     ntups;
6877         int                     i;
6878         PQExpBuffer query;
6879         TSTemplateInfo *tmplinfo;
6880         int                     i_tableoid;
6881         int                     i_oid;
6882         int                     i_tmplname;
6883         int                     i_tmplnamespace;
6884         int                     i_tmplinit;
6885         int                     i_tmpllexize;
6886
6887         /* Before 8.3, there is no built-in text search support */
6888         if (fout->remoteVersion < 80300)
6889         {
6890                 *numTSTemplates = 0;
6891                 return NULL;
6892         }
6893
6894         query = createPQExpBuffer();
6895
6896         /* Make sure we are in proper schema */
6897         selectSourceSchema(fout, "pg_catalog");
6898
6899         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6900                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6901                                           "FROM pg_ts_template");
6902
6903         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6904
6905         ntups = PQntuples(res);
6906         *numTSTemplates = ntups;
6907
6908         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6909
6910         i_tableoid = PQfnumber(res, "tableoid");
6911         i_oid = PQfnumber(res, "oid");
6912         i_tmplname = PQfnumber(res, "tmplname");
6913         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6914         i_tmplinit = PQfnumber(res, "tmplinit");
6915         i_tmpllexize = PQfnumber(res, "tmpllexize");
6916
6917         for (i = 0; i < ntups; i++)
6918         {
6919                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6920                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6921                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6922                 AssignDumpId(&tmplinfo[i].dobj);
6923                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6924                 tmplinfo[i].dobj.namespace =
6925                         findNamespace(fout,
6926                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
6927                                                   tmplinfo[i].dobj.catId.oid);
6928                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6929                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6930
6931                 /* Decide whether we want to dump it */
6932                 selectDumpableObject(&(tmplinfo[i].dobj));
6933         }
6934
6935         PQclear(res);
6936
6937         destroyPQExpBuffer(query);
6938
6939         return tmplinfo;
6940 }
6941
6942 /*
6943  * getTSConfigurations:
6944  *        read all text search configurations in the system catalogs and return
6945  *        them in the TSConfigInfo* structure
6946  *
6947  *      numTSConfigs is set to the number of configurations read in
6948  */
6949 TSConfigInfo *
6950 getTSConfigurations(Archive *fout, int *numTSConfigs)
6951 {
6952         PGresult   *res;
6953         int                     ntups;
6954         int                     i;
6955         PQExpBuffer query;
6956         TSConfigInfo *cfginfo;
6957         int                     i_tableoid;
6958         int                     i_oid;
6959         int                     i_cfgname;
6960         int                     i_cfgnamespace;
6961         int                     i_rolname;
6962         int                     i_cfgparser;
6963
6964         /* Before 8.3, there is no built-in text search support */
6965         if (fout->remoteVersion < 80300)
6966         {
6967                 *numTSConfigs = 0;
6968                 return NULL;
6969         }
6970
6971         query = createPQExpBuffer();
6972
6973         /* Make sure we are in proper schema */
6974         selectSourceSchema(fout, "pg_catalog");
6975
6976         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6977                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6978                                           "FROM pg_ts_config",
6979                                           username_subquery);
6980
6981         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6982
6983         ntups = PQntuples(res);
6984         *numTSConfigs = ntups;
6985
6986         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6987
6988         i_tableoid = PQfnumber(res, "tableoid");
6989         i_oid = PQfnumber(res, "oid");
6990         i_cfgname = PQfnumber(res, "cfgname");
6991         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
6992         i_rolname = PQfnumber(res, "rolname");
6993         i_cfgparser = PQfnumber(res, "cfgparser");
6994
6995         for (i = 0; i < ntups; i++)
6996         {
6997                 cfginfo[i].dobj.objType = DO_TSCONFIG;
6998                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6999                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7000                 AssignDumpId(&cfginfo[i].dobj);
7001                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
7002                 cfginfo[i].dobj.namespace =
7003                         findNamespace(fout,
7004                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
7005                                                   cfginfo[i].dobj.catId.oid);
7006                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7007                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7008
7009                 /* Decide whether we want to dump it */
7010                 selectDumpableObject(&(cfginfo[i].dobj));
7011         }
7012
7013         PQclear(res);
7014
7015         destroyPQExpBuffer(query);
7016
7017         return cfginfo;
7018 }
7019
7020 /*
7021  * getForeignDataWrappers:
7022  *        read all foreign-data wrappers in the system catalogs and return
7023  *        them in the FdwInfo* structure
7024  *
7025  *      numForeignDataWrappers is set to the number of fdws read in
7026  */
7027 FdwInfo *
7028 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7029 {
7030         PGresult   *res;
7031         int                     ntups;
7032         int                     i;
7033         PQExpBuffer query = createPQExpBuffer();
7034         FdwInfo    *fdwinfo;
7035         int                     i_tableoid;
7036         int                     i_oid;
7037         int                     i_fdwname;
7038         int                     i_rolname;
7039         int                     i_fdwhandler;
7040         int                     i_fdwvalidator;
7041         int                     i_fdwacl;
7042         int                     i_fdwoptions;
7043
7044         /* Before 8.4, there are no foreign-data wrappers */
7045         if (fout->remoteVersion < 80400)
7046         {
7047                 *numForeignDataWrappers = 0;
7048                 return NULL;
7049         }
7050
7051         /* Make sure we are in proper schema */
7052         selectSourceSchema(fout, "pg_catalog");
7053
7054         if (fout->remoteVersion >= 90100)
7055         {
7056                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7057                                                   "(%s fdwowner) AS rolname, "
7058                                                   "fdwhandler::pg_catalog.regproc, "
7059                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7060                                                   "array_to_string(ARRAY("
7061                                                   "SELECT quote_ident(option_name) || ' ' || "
7062                                                   "quote_literal(option_value) "
7063                                                   "FROM pg_options_to_table(fdwoptions) "
7064                                                   "ORDER BY option_name"
7065                                                   "), E',\n    ') AS fdwoptions "
7066                                                   "FROM pg_foreign_data_wrapper",
7067                                                   username_subquery);
7068         }
7069         else
7070         {
7071                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7072                                                   "(%s fdwowner) AS rolname, "
7073                                                   "'-' AS fdwhandler, "
7074                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7075                                                   "array_to_string(ARRAY("
7076                                                   "SELECT quote_ident(option_name) || ' ' || "
7077                                                   "quote_literal(option_value) "
7078                                                   "FROM pg_options_to_table(fdwoptions) "
7079                                                   "ORDER BY option_name"
7080                                                   "), E',\n    ') AS fdwoptions "
7081                                                   "FROM pg_foreign_data_wrapper",
7082                                                   username_subquery);
7083         }
7084
7085         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7086
7087         ntups = PQntuples(res);
7088         *numForeignDataWrappers = ntups;
7089
7090         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7091
7092         i_tableoid = PQfnumber(res, "tableoid");
7093         i_oid = PQfnumber(res, "oid");
7094         i_fdwname = PQfnumber(res, "fdwname");
7095         i_rolname = PQfnumber(res, "rolname");
7096         i_fdwhandler = PQfnumber(res, "fdwhandler");
7097         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7098         i_fdwacl = PQfnumber(res, "fdwacl");
7099         i_fdwoptions = PQfnumber(res, "fdwoptions");
7100
7101         for (i = 0; i < ntups; i++)
7102         {
7103                 fdwinfo[i].dobj.objType = DO_FDW;
7104                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7105                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7106                 AssignDumpId(&fdwinfo[i].dobj);
7107                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7108                 fdwinfo[i].dobj.namespace = NULL;
7109                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7110                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7111                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7112                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7113                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7114
7115                 /* Decide whether we want to dump it */
7116                 selectDumpableObject(&(fdwinfo[i].dobj));
7117         }
7118
7119         PQclear(res);
7120
7121         destroyPQExpBuffer(query);
7122
7123         return fdwinfo;
7124 }
7125
7126 /*
7127  * getForeignServers:
7128  *        read all foreign servers in the system catalogs and return
7129  *        them in the ForeignServerInfo * structure
7130  *
7131  *      numForeignServers is set to the number of servers read in
7132  */
7133 ForeignServerInfo *
7134 getForeignServers(Archive *fout, int *numForeignServers)
7135 {
7136         PGresult   *res;
7137         int                     ntups;
7138         int                     i;
7139         PQExpBuffer query = createPQExpBuffer();
7140         ForeignServerInfo *srvinfo;
7141         int                     i_tableoid;
7142         int                     i_oid;
7143         int                     i_srvname;
7144         int                     i_rolname;
7145         int                     i_srvfdw;
7146         int                     i_srvtype;
7147         int                     i_srvversion;
7148         int                     i_srvacl;
7149         int                     i_srvoptions;
7150
7151         /* Before 8.4, there are no foreign servers */
7152         if (fout->remoteVersion < 80400)
7153         {
7154                 *numForeignServers = 0;
7155                 return NULL;
7156         }
7157
7158         /* Make sure we are in proper schema */
7159         selectSourceSchema(fout, "pg_catalog");
7160
7161         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7162                                           "(%s srvowner) AS rolname, "
7163                                           "srvfdw, srvtype, srvversion, srvacl,"
7164                                           "array_to_string(ARRAY("
7165                                           "SELECT quote_ident(option_name) || ' ' || "
7166                                           "quote_literal(option_value) "
7167                                           "FROM pg_options_to_table(srvoptions) "
7168                                           "ORDER BY option_name"
7169                                           "), E',\n    ') AS srvoptions "
7170                                           "FROM pg_foreign_server",
7171                                           username_subquery);
7172
7173         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7174
7175         ntups = PQntuples(res);
7176         *numForeignServers = ntups;
7177
7178         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7179
7180         i_tableoid = PQfnumber(res, "tableoid");
7181         i_oid = PQfnumber(res, "oid");
7182         i_srvname = PQfnumber(res, "srvname");
7183         i_rolname = PQfnumber(res, "rolname");
7184         i_srvfdw = PQfnumber(res, "srvfdw");
7185         i_srvtype = PQfnumber(res, "srvtype");
7186         i_srvversion = PQfnumber(res, "srvversion");
7187         i_srvacl = PQfnumber(res, "srvacl");
7188         i_srvoptions = PQfnumber(res, "srvoptions");
7189
7190         for (i = 0; i < ntups; i++)
7191         {
7192                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7193                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7194                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7195                 AssignDumpId(&srvinfo[i].dobj);
7196                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7197                 srvinfo[i].dobj.namespace = NULL;
7198                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7199                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7200                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7201                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7202                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7203                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7204
7205                 /* Decide whether we want to dump it */
7206                 selectDumpableObject(&(srvinfo[i].dobj));
7207         }
7208
7209         PQclear(res);
7210
7211         destroyPQExpBuffer(query);
7212
7213         return srvinfo;
7214 }
7215
7216 /*
7217  * getDefaultACLs:
7218  *        read all default ACL information in the system catalogs and return
7219  *        them in the DefaultACLInfo structure
7220  *
7221  *      numDefaultACLs is set to the number of ACLs read in
7222  */
7223 DefaultACLInfo *
7224 getDefaultACLs(Archive *fout, int *numDefaultACLs)
7225 {
7226         DefaultACLInfo *daclinfo;
7227         PQExpBuffer query;
7228         PGresult   *res;
7229         int                     i_oid;
7230         int                     i_tableoid;
7231         int                     i_defaclrole;
7232         int                     i_defaclnamespace;
7233         int                     i_defaclobjtype;
7234         int                     i_defaclacl;
7235         int                     i,
7236                                 ntups;
7237
7238         if (fout->remoteVersion < 90000)
7239         {
7240                 *numDefaultACLs = 0;
7241                 return NULL;
7242         }
7243
7244         query = createPQExpBuffer();
7245
7246         /* Make sure we are in proper schema */
7247         selectSourceSchema(fout, "pg_catalog");
7248
7249         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7250                                           "(%s defaclrole) AS defaclrole, "
7251                                           "defaclnamespace, "
7252                                           "defaclobjtype, "
7253                                           "defaclacl "
7254                                           "FROM pg_default_acl",
7255                                           username_subquery);
7256
7257         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7258
7259         ntups = PQntuples(res);
7260         *numDefaultACLs = ntups;
7261
7262         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7263
7264         i_oid = PQfnumber(res, "oid");
7265         i_tableoid = PQfnumber(res, "tableoid");
7266         i_defaclrole = PQfnumber(res, "defaclrole");
7267         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7268         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7269         i_defaclacl = PQfnumber(res, "defaclacl");
7270
7271         for (i = 0; i < ntups; i++)
7272         {
7273                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7274
7275                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7276                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7277                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7278                 AssignDumpId(&daclinfo[i].dobj);
7279                 /* cheesy ... is it worth coming up with a better object name? */
7280                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7281
7282                 if (nspid != InvalidOid)
7283                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7284                                                                                                  daclinfo[i].dobj.catId.oid);
7285                 else
7286                         daclinfo[i].dobj.namespace = NULL;
7287
7288                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7289                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7290                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7291
7292                 /* Decide whether we want to dump it */
7293                 selectDumpableDefaultACL(&(daclinfo[i]));
7294         }
7295
7296         PQclear(res);
7297
7298         destroyPQExpBuffer(query);
7299
7300         return daclinfo;
7301 }
7302
7303 /*
7304  * dumpComment --
7305  *
7306  * This routine is used to dump any comments associated with the
7307  * object handed to this routine. The routine takes a constant character
7308  * string for the target part of the comment-creation command, plus
7309  * the namespace and owner of the object (for labeling the ArchiveEntry),
7310  * plus catalog ID and subid which are the lookup key for pg_description,
7311  * plus the dump ID for the object (for setting a dependency).
7312  * If a matching pg_description entry is found, it is dumped.
7313  *
7314  * Note: although this routine takes a dumpId for dependency purposes,
7315  * that purpose is just to mark the dependency in the emitted dump file
7316  * for possible future use by pg_restore.  We do NOT use it for determining
7317  * ordering of the comment in the dump file, because this routine is called
7318  * after dependency sorting occurs.  This routine should be called just after
7319  * calling ArchiveEntry() for the specified object.
7320  */
7321 static void
7322 dumpComment(Archive *fout, const char *target,
7323                         const char *namespace, const char *owner,
7324                         CatalogId catalogId, int subid, DumpId dumpId)
7325 {
7326         CommentItem *comments;
7327         int                     ncomments;
7328
7329         /* Comments are schema not data ... except blob comments are data */
7330         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7331         {
7332                 if (dataOnly)
7333                         return;
7334         }
7335         else
7336         {
7337                 if (schemaOnly)
7338                         return;
7339         }
7340
7341         /* Search for comments associated with catalogId, using table */
7342         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7343                                                          &comments);
7344
7345         /* Is there one matching the subid? */
7346         while (ncomments > 0)
7347         {
7348                 if (comments->objsubid == subid)
7349                         break;
7350                 comments++;
7351                 ncomments--;
7352         }
7353
7354         /* If a comment exists, build COMMENT ON statement */
7355         if (ncomments > 0)
7356         {
7357                 PQExpBuffer query = createPQExpBuffer();
7358
7359                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7360                 appendStringLiteralAH(query, comments->descr, fout);
7361                 appendPQExpBuffer(query, ";\n");
7362
7363                 /*
7364                  * We mark comments as SECTION_NONE because they really belong in the
7365                  * same section as their parent, whether that is pre-data or
7366                  * post-data.
7367                  */
7368                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7369                                          target, namespace, NULL, owner,
7370                                          false, "COMMENT", SECTION_NONE,
7371                                          query->data, "", NULL,
7372                                          &(dumpId), 1,
7373                                          NULL, NULL);
7374
7375                 destroyPQExpBuffer(query);
7376         }
7377 }
7378
7379 /*
7380  * dumpTableComment --
7381  *
7382  * As above, but dump comments for both the specified table (or view)
7383  * and its columns.
7384  */
7385 static void
7386 dumpTableComment(Archive *fout, TableInfo *tbinfo,
7387                                  const char *reltypename)
7388 {
7389         CommentItem *comments;
7390         int                     ncomments;
7391         PQExpBuffer query;
7392         PQExpBuffer target;
7393
7394         /* Comments are SCHEMA not data */
7395         if (dataOnly)
7396                 return;
7397
7398         /* Search for comments associated with relation, using table */
7399         ncomments = findComments(fout,
7400                                                          tbinfo->dobj.catId.tableoid,
7401                                                          tbinfo->dobj.catId.oid,
7402                                                          &comments);
7403
7404         /* If comments exist, build COMMENT ON statements */
7405         if (ncomments <= 0)
7406                 return;
7407
7408         query = createPQExpBuffer();
7409         target = createPQExpBuffer();
7410
7411         while (ncomments > 0)
7412         {
7413                 const char *descr = comments->descr;
7414                 int                     objsubid = comments->objsubid;
7415
7416                 if (objsubid == 0)
7417                 {
7418                         resetPQExpBuffer(target);
7419                         appendPQExpBuffer(target, "%s %s", reltypename,
7420                                                           fmtId(tbinfo->dobj.name));
7421
7422                         resetPQExpBuffer(query);
7423                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7424                         appendStringLiteralAH(query, descr, fout);
7425                         appendPQExpBuffer(query, ";\n");
7426
7427                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7428                                                  target->data,
7429                                                  tbinfo->dobj.namespace->dobj.name,
7430                                                  NULL, tbinfo->rolname,
7431                                                  false, "COMMENT", SECTION_NONE,
7432                                                  query->data, "", NULL,
7433                                                  &(tbinfo->dobj.dumpId), 1,
7434                                                  NULL, NULL);
7435                 }
7436                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7437                 {
7438                         resetPQExpBuffer(target);
7439                         appendPQExpBuffer(target, "COLUMN %s.",
7440                                                           fmtId(tbinfo->dobj.name));
7441                         appendPQExpBuffer(target, "%s",
7442                                                           fmtId(tbinfo->attnames[objsubid - 1]));
7443
7444                         resetPQExpBuffer(query);
7445                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7446                         appendStringLiteralAH(query, descr, fout);
7447                         appendPQExpBuffer(query, ";\n");
7448
7449                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7450                                                  target->data,
7451                                                  tbinfo->dobj.namespace->dobj.name,
7452                                                  NULL, tbinfo->rolname,
7453                                                  false, "COMMENT", SECTION_NONE,
7454                                                  query->data, "", NULL,
7455                                                  &(tbinfo->dobj.dumpId), 1,
7456                                                  NULL, NULL);
7457                 }
7458
7459                 comments++;
7460                 ncomments--;
7461         }
7462
7463         destroyPQExpBuffer(query);
7464         destroyPQExpBuffer(target);
7465 }
7466
7467 /*
7468  * findComments --
7469  *
7470  * Find the comment(s), if any, associated with the given object.  All the
7471  * objsubid values associated with the given classoid/objoid are found with
7472  * one search.
7473  */
7474 static int
7475 findComments(Archive *fout, Oid classoid, Oid objoid,
7476                          CommentItem **items)
7477 {
7478         /* static storage for table of comments */
7479         static CommentItem *comments = NULL;
7480         static int      ncomments = -1;
7481
7482         CommentItem *middle = NULL;
7483         CommentItem *low;
7484         CommentItem *high;
7485         int                     nmatch;
7486
7487         /* Get comments if we didn't already */
7488         if (ncomments < 0)
7489                 ncomments = collectComments(fout, &comments);
7490
7491         /*
7492          * Pre-7.2, pg_description does not contain classoid, so collectComments
7493          * just stores a zero.  If there's a collision on object OID, well, you
7494          * get duplicate comments.
7495          */
7496         if (fout->remoteVersion < 70200)
7497                 classoid = 0;
7498
7499         /*
7500          * Do binary search to find some item matching the object.
7501          */
7502         low = &comments[0];
7503         high = &comments[ncomments - 1];
7504         while (low <= high)
7505         {
7506                 middle = low + (high - low) / 2;
7507
7508                 if (classoid < middle->classoid)
7509                         high = middle - 1;
7510                 else if (classoid > middle->classoid)
7511                         low = middle + 1;
7512                 else if (objoid < middle->objoid)
7513                         high = middle - 1;
7514                 else if (objoid > middle->objoid)
7515                         low = middle + 1;
7516                 else
7517                         break;                          /* found a match */
7518         }
7519
7520         if (low > high)                         /* no matches */
7521         {
7522                 *items = NULL;
7523                 return 0;
7524         }
7525
7526         /*
7527          * Now determine how many items match the object.  The search loop
7528          * invariant still holds: only items between low and high inclusive could
7529          * match.
7530          */
7531         nmatch = 1;
7532         while (middle > low)
7533         {
7534                 if (classoid != middle[-1].classoid ||
7535                         objoid != middle[-1].objoid)
7536                         break;
7537                 middle--;
7538                 nmatch++;
7539         }
7540
7541         *items = middle;
7542
7543         middle += nmatch;
7544         while (middle <= high)
7545         {
7546                 if (classoid != middle->classoid ||
7547                         objoid != middle->objoid)
7548                         break;
7549                 middle++;
7550                 nmatch++;
7551         }
7552
7553         return nmatch;
7554 }
7555
7556 /*
7557  * collectComments --
7558  *
7559  * Construct a table of all comments available for database objects.
7560  * We used to do per-object queries for the comments, but it's much faster
7561  * to pull them all over at once, and on most databases the memory cost
7562  * isn't high.
7563  *
7564  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7565  */
7566 static int
7567 collectComments(Archive *fout, CommentItem **items)
7568 {
7569         PGresult   *res;
7570         PQExpBuffer query;
7571         int                     i_description;
7572         int                     i_classoid;
7573         int                     i_objoid;
7574         int                     i_objsubid;
7575         int                     ntups;
7576         int                     i;
7577         CommentItem *comments;
7578
7579         /*
7580          * Note we do NOT change source schema here; preserve the caller's
7581          * setting, instead.
7582          */
7583
7584         query = createPQExpBuffer();
7585
7586         if (fout->remoteVersion >= 70300)
7587         {
7588                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7589                                                   "FROM pg_catalog.pg_description "
7590                                                   "ORDER BY classoid, objoid, objsubid");
7591         }
7592         else if (fout->remoteVersion >= 70200)
7593         {
7594                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7595                                                   "FROM pg_description "
7596                                                   "ORDER BY classoid, objoid, objsubid");
7597         }
7598         else
7599         {
7600                 /* Note: this will fail to find attribute comments in pre-7.2... */
7601                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7602                                                   "FROM pg_description "
7603                                                   "ORDER BY objoid");
7604         }
7605
7606         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7607
7608         /* Construct lookup table containing OIDs in numeric form */
7609
7610         i_description = PQfnumber(res, "description");
7611         i_classoid = PQfnumber(res, "classoid");
7612         i_objoid = PQfnumber(res, "objoid");
7613         i_objsubid = PQfnumber(res, "objsubid");
7614
7615         ntups = PQntuples(res);
7616
7617         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7618
7619         for (i = 0; i < ntups; i++)
7620         {
7621                 comments[i].descr = PQgetvalue(res, i, i_description);
7622                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7623                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7624                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7625         }
7626
7627         /* Do NOT free the PGresult since we are keeping pointers into it */
7628         destroyPQExpBuffer(query);
7629
7630         *items = comments;
7631         return ntups;
7632 }
7633
7634 /*
7635  * dumpDumpableObject
7636  *
7637  * This routine and its subsidiaries are responsible for creating
7638  * ArchiveEntries (TOC objects) for each object to be dumped.
7639  */
7640 static void
7641 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7642 {
7643         switch (dobj->objType)
7644         {
7645                 case DO_NAMESPACE:
7646                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7647                         break;
7648                 case DO_EXTENSION:
7649                         dumpExtension(fout, (ExtensionInfo *) dobj);
7650                         break;
7651                 case DO_TYPE:
7652                         dumpType(fout, (TypeInfo *) dobj);
7653                         break;
7654                 case DO_SHELL_TYPE:
7655                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7656                         break;
7657                 case DO_FUNC:
7658                         dumpFunc(fout, (FuncInfo *) dobj);
7659                         break;
7660                 case DO_AGG:
7661                         dumpAgg(fout, (AggInfo *) dobj);
7662                         break;
7663                 case DO_OPERATOR:
7664                         dumpOpr(fout, (OprInfo *) dobj);
7665                         break;
7666                 case DO_OPCLASS:
7667                         dumpOpclass(fout, (OpclassInfo *) dobj);
7668                         break;
7669                 case DO_OPFAMILY:
7670                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7671                         break;
7672                 case DO_COLLATION:
7673                         dumpCollation(fout, (CollInfo *) dobj);
7674                         break;
7675                 case DO_CONVERSION:
7676                         dumpConversion(fout, (ConvInfo *) dobj);
7677                         break;
7678                 case DO_TABLE:
7679                         dumpTable(fout, (TableInfo *) dobj);
7680                         break;
7681                 case DO_ATTRDEF:
7682                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7683                         break;
7684                 case DO_INDEX:
7685                         dumpIndex(fout, (IndxInfo *) dobj);
7686                         break;
7687                 case DO_REFRESH_MATVIEW:
7688                         refreshMatViewData(fout, (TableDataInfo *) dobj);
7689                         break;
7690                 case DO_RULE:
7691                         dumpRule(fout, (RuleInfo *) dobj);
7692                         break;
7693                 case DO_TRIGGER:
7694                         dumpTrigger(fout, (TriggerInfo *) dobj);
7695                         break;
7696                 case DO_EVENT_TRIGGER:
7697                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7698                         break;
7699                 case DO_CONSTRAINT:
7700                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7701                         break;
7702                 case DO_FK_CONSTRAINT:
7703                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7704                         break;
7705                 case DO_PROCLANG:
7706                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7707                         break;
7708                 case DO_CAST:
7709                         dumpCast(fout, (CastInfo *) dobj);
7710                         break;
7711                 case DO_TABLE_DATA:
7712                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
7713                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
7714                         else
7715                                 dumpTableData(fout, (TableDataInfo *) dobj);
7716                         break;
7717                 case DO_DUMMY_TYPE:
7718                         /* table rowtypes and array types are never dumped separately */
7719                         break;
7720                 case DO_TSPARSER:
7721                         dumpTSParser(fout, (TSParserInfo *) dobj);
7722                         break;
7723                 case DO_TSDICT:
7724                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7725                         break;
7726                 case DO_TSTEMPLATE:
7727                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7728                         break;
7729                 case DO_TSCONFIG:
7730                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7731                         break;
7732                 case DO_FDW:
7733                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7734                         break;
7735                 case DO_FOREIGN_SERVER:
7736                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7737                         break;
7738                 case DO_DEFAULT_ACL:
7739                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7740                         break;
7741                 case DO_BLOB:
7742                         dumpBlob(fout, (BlobInfo *) dobj);
7743                         break;
7744                 case DO_BLOB_DATA:
7745                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7746                                                  dobj->name, NULL, NULL, "",
7747                                                  false, "BLOBS", SECTION_DATA,
7748                                                  "", "", NULL,
7749                                                  NULL, 0,
7750                                                  dumpBlobs, NULL);
7751                         break;
7752                 case DO_PRE_DATA_BOUNDARY:
7753                 case DO_POST_DATA_BOUNDARY:
7754                         /* never dumped, nothing to do */
7755                         break;
7756         }
7757 }
7758
7759 /*
7760  * dumpNamespace
7761  *        writes out to fout the queries to recreate a user-defined namespace
7762  */
7763 static void
7764 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7765 {
7766         PQExpBuffer q;
7767         PQExpBuffer delq;
7768         PQExpBuffer labelq;
7769         char       *qnspname;
7770
7771         /* Skip if not to be dumped */
7772         if (!nspinfo->dobj.dump || dataOnly)
7773                 return;
7774
7775         /* don't dump dummy namespace from pre-7.3 source */
7776         if (strlen(nspinfo->dobj.name) == 0)
7777                 return;
7778
7779         q = createPQExpBuffer();
7780         delq = createPQExpBuffer();
7781         labelq = createPQExpBuffer();
7782
7783         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7784
7785         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7786
7787         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7788
7789         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7790
7791         if (binary_upgrade)
7792                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7793
7794         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7795                                  nspinfo->dobj.name,
7796                                  NULL, NULL,
7797                                  nspinfo->rolname,
7798                                  false, "SCHEMA", SECTION_PRE_DATA,
7799                                  q->data, delq->data, NULL,
7800                                  NULL, 0,
7801                                  NULL, NULL);
7802
7803         /* Dump Schema Comments and Security Labels */
7804         dumpComment(fout, labelq->data,
7805                                 NULL, nspinfo->rolname,
7806                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7807         dumpSecLabel(fout, labelq->data,
7808                                  NULL, nspinfo->rolname,
7809                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7810
7811         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7812                         qnspname, NULL, nspinfo->dobj.name, NULL,
7813                         nspinfo->rolname, nspinfo->nspacl);
7814
7815         free(qnspname);
7816
7817         destroyPQExpBuffer(q);
7818         destroyPQExpBuffer(delq);
7819         destroyPQExpBuffer(labelq);
7820 }
7821
7822 /*
7823  * dumpExtension
7824  *        writes out to fout the queries to recreate an extension
7825  */
7826 static void
7827 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7828 {
7829         PQExpBuffer q;
7830         PQExpBuffer delq;
7831         PQExpBuffer labelq;
7832         char       *qextname;
7833
7834         /* Skip if not to be dumped */
7835         if (!extinfo->dobj.dump || dataOnly)
7836                 return;
7837
7838         q = createPQExpBuffer();
7839         delq = createPQExpBuffer();
7840         labelq = createPQExpBuffer();
7841
7842         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7843
7844         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7845
7846         if (!binary_upgrade)
7847         {
7848                 /*
7849                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7850                  * problem if the extension already exists in the target database;
7851                  * this is essential for installed-by-default extensions such as
7852                  * plpgsql.
7853                  *
7854                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7855                  * built-in extensions based on their OIDs; see
7856                  * selectDumpableExtension.
7857                  */
7858                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7859                                                   qextname, fmtId(extinfo->namespace));
7860         }
7861         else
7862         {
7863                 int                     i;
7864                 int                     n;
7865
7866                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7867
7868                 /*
7869                  * We unconditionally create the extension, so we must drop it if it
7870                  * exists.      This could happen if the user deleted 'plpgsql' and then
7871                  * readded it, causing its oid to be greater than FirstNormalObjectId.
7872                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
7873                  * and recreating extensions like 'plpgsql'.
7874                  */
7875                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
7876
7877                 appendPQExpBuffer(q,
7878                                                   "SELECT binary_upgrade.create_empty_extension(");
7879                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7880                 appendPQExpBuffer(q, ", ");
7881                 appendStringLiteralAH(q, extinfo->namespace, fout);
7882                 appendPQExpBuffer(q, ", ");
7883                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7884                 appendStringLiteralAH(q, extinfo->extversion, fout);
7885                 appendPQExpBuffer(q, ", ");
7886
7887                 /*
7888                  * Note that we're pushing extconfig (an OID array) back into
7889                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7890                  * preserved in binary upgrade.
7891                  */
7892                 if (strlen(extinfo->extconfig) > 2)
7893                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7894                 else
7895                         appendPQExpBuffer(q, "NULL");
7896                 appendPQExpBuffer(q, ", ");
7897                 if (strlen(extinfo->extcondition) > 2)
7898                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7899                 else
7900                         appendPQExpBuffer(q, "NULL");
7901                 appendPQExpBuffer(q, ", ");
7902                 appendPQExpBuffer(q, "ARRAY[");
7903                 n = 0;
7904                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7905                 {
7906                         DumpableObject *extobj;
7907
7908                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7909                         if (extobj && extobj->objType == DO_EXTENSION)
7910                         {
7911                                 if (n++ > 0)
7912                                         appendPQExpBuffer(q, ",");
7913                                 appendStringLiteralAH(q, extobj->name, fout);
7914                         }
7915                 }
7916                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7917                 appendPQExpBuffer(q, ");\n");
7918         }
7919
7920         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7921
7922         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7923                                  extinfo->dobj.name,
7924                                  NULL, NULL,
7925                                  "",
7926                                  false, "EXTENSION", SECTION_PRE_DATA,
7927                                  q->data, delq->data, NULL,
7928                                  NULL, 0,
7929                                  NULL, NULL);
7930
7931         /* Dump Extension Comments and Security Labels */
7932         dumpComment(fout, labelq->data,
7933                                 NULL, "",
7934                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7935         dumpSecLabel(fout, labelq->data,
7936                                  NULL, "",
7937                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7938
7939         free(qextname);
7940
7941         destroyPQExpBuffer(q);
7942         destroyPQExpBuffer(delq);
7943         destroyPQExpBuffer(labelq);
7944 }
7945
7946 /*
7947  * dumpType
7948  *        writes out to fout the queries to recreate a user-defined type
7949  */
7950 static void
7951 dumpType(Archive *fout, TypeInfo *tyinfo)
7952 {
7953         /* Skip if not to be dumped */
7954         if (!tyinfo->dobj.dump || dataOnly)
7955                 return;
7956
7957         /* Dump out in proper style */
7958         if (tyinfo->typtype == TYPTYPE_BASE)
7959                 dumpBaseType(fout, tyinfo);
7960         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7961                 dumpDomain(fout, tyinfo);
7962         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7963                 dumpCompositeType(fout, tyinfo);
7964         else if (tyinfo->typtype == TYPTYPE_ENUM)
7965                 dumpEnumType(fout, tyinfo);
7966         else if (tyinfo->typtype == TYPTYPE_RANGE)
7967                 dumpRangeType(fout, tyinfo);
7968         else
7969                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7970                                   tyinfo->dobj.name);
7971 }
7972
7973 /*
7974  * dumpEnumType
7975  *        writes out to fout the queries to recreate a user-defined enum type
7976  */
7977 static void
7978 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7979 {
7980         PQExpBuffer q = createPQExpBuffer();
7981         PQExpBuffer delq = createPQExpBuffer();
7982         PQExpBuffer labelq = createPQExpBuffer();
7983         PQExpBuffer query = createPQExpBuffer();
7984         PGresult   *res;
7985         int                     num,
7986                                 i;
7987         Oid                     enum_oid;
7988         char       *qtypname;
7989         char       *label;
7990
7991         /* Set proper schema search path */
7992         selectSourceSchema(fout, "pg_catalog");
7993
7994         if (fout->remoteVersion >= 90100)
7995                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7996                                                   "FROM pg_catalog.pg_enum "
7997                                                   "WHERE enumtypid = '%u'"
7998                                                   "ORDER BY enumsortorder",
7999                                                   tyinfo->dobj.catId.oid);
8000         else
8001                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8002                                                   "FROM pg_catalog.pg_enum "
8003                                                   "WHERE enumtypid = '%u'"
8004                                                   "ORDER BY oid",
8005                                                   tyinfo->dobj.catId.oid);
8006
8007         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8008
8009         num = PQntuples(res);
8010
8011         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8012
8013         /*
8014          * DROP must be fully qualified in case same name appears in pg_catalog.
8015          * CASCADE shouldn't be required here as for normal types since the I/O
8016          * functions are generic and do not get dropped.
8017          */
8018         appendPQExpBuffer(delq, "DROP TYPE %s.",
8019                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8020         appendPQExpBuffer(delq, "%s;\n",
8021                                           qtypname);
8022
8023         if (binary_upgrade)
8024                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8025                                                                                                  tyinfo->dobj.catId.oid);
8026
8027         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8028                                           qtypname);
8029
8030         if (!binary_upgrade)
8031         {
8032                 /* Labels with server-assigned oids */
8033                 for (i = 0; i < num; i++)
8034                 {
8035                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8036                         if (i > 0)
8037                                 appendPQExpBuffer(q, ",");
8038                         appendPQExpBuffer(q, "\n    ");
8039                         appendStringLiteralAH(q, label, fout);
8040                 }
8041         }
8042
8043         appendPQExpBuffer(q, "\n);\n");
8044
8045         if (binary_upgrade)
8046         {
8047                 /* Labels with dump-assigned (preserved) oids */
8048                 for (i = 0; i < num; i++)
8049                 {
8050                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8051                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8052
8053                         if (i == 0)
8054                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8055                         appendPQExpBuffer(q,
8056                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8057                                                           enum_oid);
8058                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8059                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8060                         appendPQExpBuffer(q, "%s ADD VALUE ",
8061                                                           qtypname);
8062                         appendStringLiteralAH(q, label, fout);
8063                         appendPQExpBuffer(q, ";\n\n");
8064                 }
8065         }
8066
8067         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8068
8069         if (binary_upgrade)
8070                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8071
8072         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8073                                  tyinfo->dobj.name,
8074                                  tyinfo->dobj.namespace->dobj.name,
8075                                  NULL,
8076                                  tyinfo->rolname, false,
8077                                  "TYPE", SECTION_PRE_DATA,
8078                                  q->data, delq->data, NULL,
8079                                  NULL, 0,
8080                                  NULL, NULL);
8081
8082         /* Dump Type Comments and Security Labels */
8083         dumpComment(fout, labelq->data,
8084                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8085                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8086         dumpSecLabel(fout, labelq->data,
8087                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8088                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8089
8090         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8091                         qtypname, NULL, tyinfo->dobj.name,
8092                         tyinfo->dobj.namespace->dobj.name,
8093                         tyinfo->rolname, tyinfo->typacl);
8094
8095         PQclear(res);
8096         destroyPQExpBuffer(q);
8097         destroyPQExpBuffer(delq);
8098         destroyPQExpBuffer(labelq);
8099         destroyPQExpBuffer(query);
8100 }
8101
8102 /*
8103  * dumpRangeType
8104  *        writes out to fout the queries to recreate a user-defined range type
8105  */
8106 static void
8107 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
8108 {
8109         PQExpBuffer q = createPQExpBuffer();
8110         PQExpBuffer delq = createPQExpBuffer();
8111         PQExpBuffer labelq = createPQExpBuffer();
8112         PQExpBuffer query = createPQExpBuffer();
8113         PGresult   *res;
8114         Oid                     collationOid;
8115         char       *qtypname;
8116         char       *procname;
8117
8118         /*
8119          * select appropriate schema to ensure names in CREATE are properly
8120          * qualified
8121          */
8122         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8123
8124         appendPQExpBuffer(query,
8125                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8126                                           "opc.opcname AS opcname, "
8127                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8128                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8129                                           "opc.opcdefault, "
8130                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8131                                           "     ELSE rngcollation END AS collation, "
8132                                           "rngcanonical, rngsubdiff "
8133                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8134                                           "     pg_catalog.pg_opclass opc "
8135                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8136                                           "rngtypid = '%u'",
8137                                           tyinfo->dobj.catId.oid);
8138
8139         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8140
8141         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8142
8143         /*
8144          * DROP must be fully qualified in case same name appears in pg_catalog.
8145          * CASCADE shouldn't be required here as for normal types since the I/O
8146          * functions are generic and do not get dropped.
8147          */
8148         appendPQExpBuffer(delq, "DROP TYPE %s.",
8149                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8150         appendPQExpBuffer(delq, "%s;\n",
8151                                           qtypname);
8152
8153         if (binary_upgrade)
8154                 binary_upgrade_set_type_oids_by_type_oid(fout,
8155                                                                                                  q, tyinfo->dobj.catId.oid);
8156
8157         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8158                                           qtypname);
8159
8160         appendPQExpBuffer(q, "\n    subtype = %s",
8161                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8162
8163         /* print subtype_opclass only if not default for subtype */
8164         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8165         {
8166                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8167                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8168
8169                 /* always schema-qualify, don't try to be smart */
8170                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8171                                                   fmtId(nspname));
8172                 appendPQExpBuffer(q, "%s", fmtId(opcname));
8173         }
8174
8175         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8176         if (OidIsValid(collationOid))
8177         {
8178                 CollInfo   *coll = findCollationByOid(collationOid);
8179
8180                 if (coll)
8181                 {
8182                         /* always schema-qualify, don't try to be smart */
8183                         appendPQExpBuffer(q, ",\n    collation = %s.",
8184                                                           fmtId(coll->dobj.namespace->dobj.name));
8185                         appendPQExpBuffer(q, "%s",
8186                                                           fmtId(coll->dobj.name));
8187                 }
8188         }
8189
8190         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8191         if (strcmp(procname, "-") != 0)
8192                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8193
8194         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8195         if (strcmp(procname, "-") != 0)
8196                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8197
8198         appendPQExpBuffer(q, "\n);\n");
8199
8200         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8201
8202         if (binary_upgrade)
8203                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8204
8205         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8206                                  tyinfo->dobj.name,
8207                                  tyinfo->dobj.namespace->dobj.name,
8208                                  NULL,
8209                                  tyinfo->rolname, false,
8210                                  "TYPE", SECTION_PRE_DATA,
8211                                  q->data, delq->data, NULL,
8212                                  NULL, 0,
8213                                  NULL, NULL);
8214
8215         /* Dump Type Comments and Security Labels */
8216         dumpComment(fout, labelq->data,
8217                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8218                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8219         dumpSecLabel(fout, labelq->data,
8220                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8221                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8222
8223         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8224                         qtypname, NULL, tyinfo->dobj.name,
8225                         tyinfo->dobj.namespace->dobj.name,
8226                         tyinfo->rolname, tyinfo->typacl);
8227
8228         PQclear(res);
8229         destroyPQExpBuffer(q);
8230         destroyPQExpBuffer(delq);
8231         destroyPQExpBuffer(labelq);
8232         destroyPQExpBuffer(query);
8233 }
8234
8235 /*
8236  * dumpBaseType
8237  *        writes out to fout the queries to recreate a user-defined base type
8238  */
8239 static void
8240 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
8241 {
8242         PQExpBuffer q = createPQExpBuffer();
8243         PQExpBuffer delq = createPQExpBuffer();
8244         PQExpBuffer labelq = createPQExpBuffer();
8245         PQExpBuffer query = createPQExpBuffer();
8246         PGresult   *res;
8247         char       *qtypname;
8248         char       *typlen;
8249         char       *typinput;
8250         char       *typoutput;
8251         char       *typreceive;
8252         char       *typsend;
8253         char       *typmodin;
8254         char       *typmodout;
8255         char       *typanalyze;
8256         Oid                     typreceiveoid;
8257         Oid                     typsendoid;
8258         Oid                     typmodinoid;
8259         Oid                     typmodoutoid;
8260         Oid                     typanalyzeoid;
8261         char       *typcategory;
8262         char       *typispreferred;
8263         char       *typdelim;
8264         char       *typbyval;
8265         char       *typalign;
8266         char       *typstorage;
8267         char       *typcollatable;
8268         char       *typdefault;
8269         bool            typdefault_is_literal = false;
8270
8271         /* Set proper schema search path so regproc references list correctly */
8272         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8273
8274         /* Fetch type-specific details */
8275         if (fout->remoteVersion >= 90100)
8276         {
8277                 appendPQExpBuffer(query, "SELECT typlen, "
8278                                                   "typinput, typoutput, typreceive, typsend, "
8279                                                   "typmodin, typmodout, typanalyze, "
8280                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8281                                                   "typsend::pg_catalog.oid AS typsendoid, "
8282                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8283                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8284                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8285                                                   "typcategory, typispreferred, "
8286                                                   "typdelim, typbyval, typalign, typstorage, "
8287                                                   "(typcollation <> 0) AS typcollatable, "
8288                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8289                                                   "FROM pg_catalog.pg_type "
8290                                                   "WHERE oid = '%u'::pg_catalog.oid",
8291                                                   tyinfo->dobj.catId.oid);
8292         }
8293         else if (fout->remoteVersion >= 80400)
8294         {
8295                 appendPQExpBuffer(query, "SELECT typlen, "
8296                                                   "typinput, typoutput, typreceive, typsend, "
8297                                                   "typmodin, typmodout, typanalyze, "
8298                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8299                                                   "typsend::pg_catalog.oid AS typsendoid, "
8300                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8301                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8302                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8303                                                   "typcategory, typispreferred, "
8304                                                   "typdelim, typbyval, typalign, typstorage, "
8305                                                   "false AS typcollatable, "
8306                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8307                                                   "FROM pg_catalog.pg_type "
8308                                                   "WHERE oid = '%u'::pg_catalog.oid",
8309                                                   tyinfo->dobj.catId.oid);
8310         }
8311         else if (fout->remoteVersion >= 80300)
8312         {
8313                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8314                 appendPQExpBuffer(query, "SELECT typlen, "
8315                                                   "typinput, typoutput, typreceive, typsend, "
8316                                                   "typmodin, typmodout, typanalyze, "
8317                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8318                                                   "typsend::pg_catalog.oid AS typsendoid, "
8319                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8320                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8321                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8322                                                   "'U' AS typcategory, false AS typispreferred, "
8323                                                   "typdelim, typbyval, typalign, typstorage, "
8324                                                   "false AS typcollatable, "
8325                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8326                                                   "FROM pg_catalog.pg_type "
8327                                                   "WHERE oid = '%u'::pg_catalog.oid",
8328                                                   tyinfo->dobj.catId.oid);
8329         }
8330         else if (fout->remoteVersion >= 80000)
8331         {
8332                 appendPQExpBuffer(query, "SELECT typlen, "
8333                                                   "typinput, typoutput, typreceive, typsend, "
8334                                                   "'-' AS typmodin, '-' AS typmodout, "
8335                                                   "typanalyze, "
8336                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8337                                                   "typsend::pg_catalog.oid AS typsendoid, "
8338                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8339                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8340                                                   "'U' AS typcategory, false AS typispreferred, "
8341                                                   "typdelim, typbyval, typalign, typstorage, "
8342                                                   "false AS typcollatable, "
8343                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8344                                                   "FROM pg_catalog.pg_type "
8345                                                   "WHERE oid = '%u'::pg_catalog.oid",
8346                                                   tyinfo->dobj.catId.oid);
8347         }
8348         else if (fout->remoteVersion >= 70400)
8349         {
8350                 appendPQExpBuffer(query, "SELECT typlen, "
8351                                                   "typinput, typoutput, typreceive, typsend, "
8352                                                   "'-' AS typmodin, '-' AS typmodout, "
8353                                                   "'-' AS typanalyze, "
8354                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8355                                                   "typsend::pg_catalog.oid AS typsendoid, "
8356                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8357                                                   "0 AS typanalyzeoid, "
8358                                                   "'U' AS typcategory, false AS typispreferred, "
8359                                                   "typdelim, typbyval, typalign, typstorage, "
8360                                                   "false AS typcollatable, "
8361                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8362                                                   "FROM pg_catalog.pg_type "
8363                                                   "WHERE oid = '%u'::pg_catalog.oid",
8364                                                   tyinfo->dobj.catId.oid);
8365         }
8366         else if (fout->remoteVersion >= 70300)
8367         {
8368                 appendPQExpBuffer(query, "SELECT typlen, "
8369                                                   "typinput, typoutput, "
8370                                                   "'-' AS typreceive, '-' AS typsend, "
8371                                                   "'-' AS typmodin, '-' AS typmodout, "
8372                                                   "'-' AS typanalyze, "
8373                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8374                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8375                                                   "0 AS typanalyzeoid, "
8376                                                   "'U' AS typcategory, false AS typispreferred, "
8377                                                   "typdelim, typbyval, typalign, typstorage, "
8378                                                   "false AS typcollatable, "
8379                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8380                                                   "FROM pg_catalog.pg_type "
8381                                                   "WHERE oid = '%u'::pg_catalog.oid",
8382                                                   tyinfo->dobj.catId.oid);
8383         }
8384         else if (fout->remoteVersion >= 70200)
8385         {
8386                 /*
8387                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8388                  * ignore them because they are not right.
8389                  */
8390                 appendPQExpBuffer(query, "SELECT typlen, "
8391                                                   "typinput, typoutput, "
8392                                                   "'-' AS typreceive, '-' AS typsend, "
8393                                                   "'-' AS typmodin, '-' AS typmodout, "
8394                                                   "'-' AS typanalyze, "
8395                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8396                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8397                                                   "0 AS typanalyzeoid, "
8398                                                   "'U' AS typcategory, false AS typispreferred, "
8399                                                   "typdelim, typbyval, typalign, typstorage, "
8400                                                   "false AS typcollatable, "
8401                                                   "NULL AS typdefaultbin, typdefault "
8402                                                   "FROM pg_type "
8403                                                   "WHERE oid = '%u'::oid",
8404                                                   tyinfo->dobj.catId.oid);
8405         }
8406         else if (fout->remoteVersion >= 70100)
8407         {
8408                 /*
8409                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8410                  * representation.
8411                  */
8412                 appendPQExpBuffer(query, "SELECT typlen, "
8413                                                   "typinput, typoutput, "
8414                                                   "'-' AS typreceive, '-' AS typsend, "
8415                                                   "'-' AS typmodin, '-' AS typmodout, "
8416                                                   "'-' AS typanalyze, "
8417                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8418                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8419                                                   "0 AS typanalyzeoid, "
8420                                                   "'U' AS typcategory, false AS typispreferred, "
8421                                                   "typdelim, typbyval, typalign, typstorage, "
8422                                                   "false AS typcollatable, "
8423                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8424                                                   "FROM pg_type "
8425                                                   "WHERE oid = '%u'::oid",
8426                                                   tyinfo->dobj.catId.oid);
8427         }
8428         else
8429         {
8430                 appendPQExpBuffer(query, "SELECT typlen, "
8431                                                   "typinput, typoutput, "
8432                                                   "'-' AS typreceive, '-' AS typsend, "
8433                                                   "'-' AS typmodin, '-' AS typmodout, "
8434                                                   "'-' AS typanalyze, "
8435                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8436                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8437                                                   "0 AS typanalyzeoid, "
8438                                                   "'U' AS typcategory, false AS typispreferred, "
8439                                                   "typdelim, typbyval, typalign, "
8440                                                   "'p'::char AS typstorage, "
8441                                                   "false AS typcollatable, "
8442                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8443                                                   "FROM pg_type "
8444                                                   "WHERE oid = '%u'::oid",
8445                                                   tyinfo->dobj.catId.oid);
8446         }
8447
8448         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8449
8450         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8451         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8452         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8453         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8454         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8455         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8456         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8457         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8458         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8459         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8460         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8461         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8462         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8463         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8464         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8465         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8466         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8467         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8468         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8469         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8470         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8471                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8472         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8473         {
8474                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8475                 typdefault_is_literal = true;   /* it needs quotes */
8476         }
8477         else
8478                 typdefault = NULL;
8479
8480         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8481
8482         /*
8483          * DROP must be fully qualified in case same name appears in pg_catalog.
8484          * The reason we include CASCADE is that the circular dependency between
8485          * the type and its I/O functions makes it impossible to drop the type any
8486          * other way.
8487          */
8488         appendPQExpBuffer(delq, "DROP TYPE %s.",
8489                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8490         appendPQExpBuffer(delq, "%s CASCADE;\n",
8491                                           qtypname);
8492
8493         /* We might already have a shell type, but setting pg_type_oid is harmless */
8494         if (binary_upgrade)
8495                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8496                                                                                                  tyinfo->dobj.catId.oid);
8497
8498         appendPQExpBuffer(q,
8499                                           "CREATE TYPE %s (\n"
8500                                           "    INTERNALLENGTH = %s",
8501                                           qtypname,
8502                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8503
8504         if (fout->remoteVersion >= 70300)
8505         {
8506                 /* regproc result is correctly quoted as of 7.3 */
8507                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8508                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8509                 if (OidIsValid(typreceiveoid))
8510                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8511                 if (OidIsValid(typsendoid))
8512                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8513                 if (OidIsValid(typmodinoid))
8514                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8515                 if (OidIsValid(typmodoutoid))
8516                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8517                 if (OidIsValid(typanalyzeoid))
8518                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8519         }
8520         else
8521         {
8522                 /* regproc delivers an unquoted name before 7.3 */
8523                 /* cannot combine these because fmtId uses static result area */
8524                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8525                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8526                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8527         }
8528
8529         if (strcmp(typcollatable, "t") == 0)
8530                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8531
8532         if (typdefault != NULL)
8533         {
8534                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8535                 if (typdefault_is_literal)
8536                         appendStringLiteralAH(q, typdefault, fout);
8537                 else
8538                         appendPQExpBufferStr(q, typdefault);
8539         }
8540
8541         if (OidIsValid(tyinfo->typelem))
8542         {
8543                 char       *elemType;
8544
8545                 /* reselect schema in case changed by function dump */
8546                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8547                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8548                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8549                 free(elemType);
8550         }
8551
8552         if (strcmp(typcategory, "U") != 0)
8553         {
8554                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8555                 appendStringLiteralAH(q, typcategory, fout);
8556         }
8557
8558         if (strcmp(typispreferred, "t") == 0)
8559                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8560
8561         if (typdelim && strcmp(typdelim, ",") != 0)
8562         {
8563                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8564                 appendStringLiteralAH(q, typdelim, fout);
8565         }
8566
8567         if (strcmp(typalign, "c") == 0)
8568                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8569         else if (strcmp(typalign, "s") == 0)
8570                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8571         else if (strcmp(typalign, "i") == 0)
8572                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8573         else if (strcmp(typalign, "d") == 0)
8574                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8575
8576         if (strcmp(typstorage, "p") == 0)
8577                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8578         else if (strcmp(typstorage, "e") == 0)
8579                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8580         else if (strcmp(typstorage, "x") == 0)
8581                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8582         else if (strcmp(typstorage, "m") == 0)
8583                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8584
8585         if (strcmp(typbyval, "t") == 0)
8586                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8587
8588         appendPQExpBuffer(q, "\n);\n");
8589
8590         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8591
8592         if (binary_upgrade)
8593                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8594
8595         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8596                                  tyinfo->dobj.name,
8597                                  tyinfo->dobj.namespace->dobj.name,
8598                                  NULL,
8599                                  tyinfo->rolname, false,
8600                                  "TYPE", SECTION_PRE_DATA,
8601                                  q->data, delq->data, NULL,
8602                                  NULL, 0,
8603                                  NULL, NULL);
8604
8605         /* Dump Type Comments and Security Labels */
8606         dumpComment(fout, labelq->data,
8607                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8608                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8609         dumpSecLabel(fout, labelq->data,
8610                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8611                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8612
8613         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8614                         qtypname, NULL, tyinfo->dobj.name,
8615                         tyinfo->dobj.namespace->dobj.name,
8616                         tyinfo->rolname, tyinfo->typacl);
8617
8618         PQclear(res);
8619         destroyPQExpBuffer(q);
8620         destroyPQExpBuffer(delq);
8621         destroyPQExpBuffer(labelq);
8622         destroyPQExpBuffer(query);
8623 }
8624
8625 /*
8626  * dumpDomain
8627  *        writes out to fout the queries to recreate a user-defined domain
8628  */
8629 static void
8630 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8631 {
8632         PQExpBuffer q = createPQExpBuffer();
8633         PQExpBuffer delq = createPQExpBuffer();
8634         PQExpBuffer labelq = createPQExpBuffer();
8635         PQExpBuffer query = createPQExpBuffer();
8636         PGresult   *res;
8637         int                     i;
8638         char       *qtypname;
8639         char       *typnotnull;
8640         char       *typdefn;
8641         char       *typdefault;
8642         Oid                     typcollation;
8643         bool            typdefault_is_literal = false;
8644
8645         /* Set proper schema search path so type references list correctly */
8646         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8647
8648         /* Fetch domain specific details */
8649         if (fout->remoteVersion >= 90100)
8650         {
8651                 /* typcollation is new in 9.1 */
8652                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8653                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8654                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8655                                                   "t.typdefault, "
8656                                                   "CASE WHEN t.typcollation <> u.typcollation "
8657                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8658                                                   "FROM pg_catalog.pg_type t "
8659                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8660                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8661                                                   tyinfo->dobj.catId.oid);
8662         }
8663         else
8664         {
8665                 /* We assume here that remoteVersion must be at least 70300 */
8666                 appendPQExpBuffer(query, "SELECT typnotnull, "
8667                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8668                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8669                                                   "typdefault, 0 AS typcollation "
8670                                                   "FROM pg_catalog.pg_type "
8671                                                   "WHERE oid = '%u'::pg_catalog.oid",
8672                                                   tyinfo->dobj.catId.oid);
8673         }
8674
8675         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8676
8677         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8678         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8679         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8680                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8681         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8682         {
8683                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8684                 typdefault_is_literal = true;   /* it needs quotes */
8685         }
8686         else
8687                 typdefault = NULL;
8688         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8689
8690         if (binary_upgrade)
8691                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8692                                                                                                  tyinfo->dobj.catId.oid);
8693
8694         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8695
8696         appendPQExpBuffer(q,
8697                                           "CREATE DOMAIN %s AS %s",
8698                                           qtypname,
8699                                           typdefn);
8700
8701         /* Print collation only if different from base type's collation */
8702         if (OidIsValid(typcollation))
8703         {
8704                 CollInfo   *coll;
8705
8706                 coll = findCollationByOid(typcollation);
8707                 if (coll)
8708                 {
8709                         /* always schema-qualify, don't try to be smart */
8710                         appendPQExpBuffer(q, " COLLATE %s.",
8711                                                           fmtId(coll->dobj.namespace->dobj.name));
8712                         appendPQExpBuffer(q, "%s",
8713                                                           fmtId(coll->dobj.name));
8714                 }
8715         }
8716
8717         if (typnotnull[0] == 't')
8718                 appendPQExpBuffer(q, " NOT NULL");
8719
8720         if (typdefault != NULL)
8721         {
8722                 appendPQExpBuffer(q, " DEFAULT ");
8723                 if (typdefault_is_literal)
8724                         appendStringLiteralAH(q, typdefault, fout);
8725                 else
8726                         appendPQExpBufferStr(q, typdefault);
8727         }
8728
8729         PQclear(res);
8730
8731         /*
8732          * Add any CHECK constraints for the domain
8733          */
8734         for (i = 0; i < tyinfo->nDomChecks; i++)
8735         {
8736                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8737
8738                 if (!domcheck->separate)
8739                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8740                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8741         }
8742
8743         appendPQExpBuffer(q, ";\n");
8744
8745         /*
8746          * DROP must be fully qualified in case same name appears in pg_catalog
8747          */
8748         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8749                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8750         appendPQExpBuffer(delq, "%s;\n",
8751                                           qtypname);
8752
8753         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
8754
8755         if (binary_upgrade)
8756                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8757
8758         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8759                                  tyinfo->dobj.name,
8760                                  tyinfo->dobj.namespace->dobj.name,
8761                                  NULL,
8762                                  tyinfo->rolname, false,
8763                                  "DOMAIN", SECTION_PRE_DATA,
8764                                  q->data, delq->data, NULL,
8765                                  NULL, 0,
8766                                  NULL, NULL);
8767
8768         /* Dump Domain Comments and Security Labels */
8769         dumpComment(fout, labelq->data,
8770                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8771                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8772         dumpSecLabel(fout, labelq->data,
8773                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8774                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8775
8776         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8777                         qtypname, NULL, tyinfo->dobj.name,
8778                         tyinfo->dobj.namespace->dobj.name,
8779                         tyinfo->rolname, tyinfo->typacl);
8780
8781         destroyPQExpBuffer(q);
8782         destroyPQExpBuffer(delq);
8783         destroyPQExpBuffer(labelq);
8784         destroyPQExpBuffer(query);
8785 }
8786
8787 /*
8788  * dumpCompositeType
8789  *        writes out to fout the queries to recreate a user-defined stand-alone
8790  *        composite type
8791  */
8792 static void
8793 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8794 {
8795         PQExpBuffer q = createPQExpBuffer();
8796         PQExpBuffer dropped = createPQExpBuffer();
8797         PQExpBuffer delq = createPQExpBuffer();
8798         PQExpBuffer labelq = createPQExpBuffer();
8799         PQExpBuffer query = createPQExpBuffer();
8800         PGresult   *res;
8801         char       *qtypname;
8802         int                     ntups;
8803         int                     i_attname;
8804         int                     i_atttypdefn;
8805         int                     i_attlen;
8806         int                     i_attalign;
8807         int                     i_attisdropped;
8808         int                     i_attcollation;
8809         int                     i_typrelid;
8810         int                     i;
8811         int                     actual_atts;
8812
8813         /* Set proper schema search path so type references list correctly */
8814         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8815
8816         /* Fetch type specific details */
8817         if (fout->remoteVersion >= 90100)
8818         {
8819                 /*
8820                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8821                  * clauses for attributes whose collation is different from their
8822                  * type's default, we use a CASE here to suppress uninteresting
8823                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8824                  * collation does not matter for those.
8825                  */
8826                 appendPQExpBuffer(query, "SELECT a.attname, "
8827                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8828                                                   "a.attlen, a.attalign, a.attisdropped, "
8829                                                   "CASE WHEN a.attcollation <> at.typcollation "
8830                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8831                                                   "ct.typrelid "
8832                                                   "FROM pg_catalog.pg_type ct "
8833                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8834                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8835                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8836                                                   "ORDER BY a.attnum ",
8837                                                   tyinfo->dobj.catId.oid);
8838         }
8839         else
8840         {
8841                 /*
8842                  * We assume here that remoteVersion must be at least 70300.  Since
8843                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8844                  * always be false.
8845                  */
8846                 appendPQExpBuffer(query, "SELECT a.attname, "
8847                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8848                                                   "a.attlen, a.attalign, a.attisdropped, "
8849                                                   "0 AS attcollation, "
8850                                                   "ct.typrelid "
8851                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8852                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8853                                                   "AND a.attrelid = ct.typrelid "
8854                                                   "ORDER BY a.attnum ",
8855                                                   tyinfo->dobj.catId.oid);
8856         }
8857
8858         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8859
8860         ntups = PQntuples(res);
8861
8862         i_attname = PQfnumber(res, "attname");
8863         i_atttypdefn = PQfnumber(res, "atttypdefn");
8864         i_attlen = PQfnumber(res, "attlen");
8865         i_attalign = PQfnumber(res, "attalign");
8866         i_attisdropped = PQfnumber(res, "attisdropped");
8867         i_attcollation = PQfnumber(res, "attcollation");
8868         i_typrelid = PQfnumber(res, "typrelid");
8869
8870         if (binary_upgrade)
8871         {
8872                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8873
8874                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8875                                                                                                  tyinfo->dobj.catId.oid);
8876                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
8877         }
8878
8879         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8880
8881         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8882                                           qtypname);
8883
8884         actual_atts = 0;
8885         for (i = 0; i < ntups; i++)
8886         {
8887                 char       *attname;
8888                 char       *atttypdefn;
8889                 char       *attlen;
8890                 char       *attalign;
8891                 bool            attisdropped;
8892                 Oid                     attcollation;
8893
8894                 attname = PQgetvalue(res, i, i_attname);
8895                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8896                 attlen = PQgetvalue(res, i, i_attlen);
8897                 attalign = PQgetvalue(res, i, i_attalign);
8898                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8899                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8900
8901                 if (attisdropped && !binary_upgrade)
8902                         continue;
8903
8904                 /* Format properly if not first attr */
8905                 if (actual_atts++ > 0)
8906                         appendPQExpBuffer(q, ",");
8907                 appendPQExpBuffer(q, "\n\t");
8908
8909                 if (!attisdropped)
8910                 {
8911                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8912
8913                         /* Add collation if not default for the column type */
8914                         if (OidIsValid(attcollation))
8915                         {
8916                                 CollInfo   *coll;
8917
8918                                 coll = findCollationByOid(attcollation);
8919                                 if (coll)
8920                                 {
8921                                         /* always schema-qualify, don't try to be smart */
8922                                         appendPQExpBuffer(q, " COLLATE %s.",
8923                                                                           fmtId(coll->dobj.namespace->dobj.name));
8924                                         appendPQExpBuffer(q, "%s",
8925                                                                           fmtId(coll->dobj.name));
8926                                 }
8927                         }
8928                 }
8929                 else
8930                 {
8931                         /*
8932                          * This is a dropped attribute and we're in binary_upgrade mode.
8933                          * Insert a placeholder for it in the CREATE TYPE command, and set
8934                          * length and alignment with direct UPDATE to the catalogs
8935                          * afterwards. See similar code in dumpTableSchema().
8936                          */
8937                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8938
8939                         /* stash separately for insertion after the CREATE TYPE */
8940                         appendPQExpBuffer(dropped,
8941                                           "\n-- For binary upgrade, recreate dropped column.\n");
8942                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8943                                                           "SET attlen = %s, "
8944                                                           "attalign = '%s', attbyval = false\n"
8945                                                           "WHERE attname = ", attlen, attalign);
8946                         appendStringLiteralAH(dropped, attname, fout);
8947                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8948                         appendStringLiteralAH(dropped, qtypname, fout);
8949                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8950
8951                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8952                                                           qtypname);
8953                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8954                                                           fmtId(attname));
8955                 }
8956         }
8957         appendPQExpBuffer(q, "\n);\n");
8958         appendPQExpBufferStr(q, dropped->data);
8959
8960         /*
8961          * DROP must be fully qualified in case same name appears in pg_catalog
8962          */
8963         appendPQExpBuffer(delq, "DROP TYPE %s.",
8964                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8965         appendPQExpBuffer(delq, "%s;\n",
8966                                           qtypname);
8967
8968         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8969
8970         if (binary_upgrade)
8971                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8972
8973         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8974                                  tyinfo->dobj.name,
8975                                  tyinfo->dobj.namespace->dobj.name,
8976                                  NULL,
8977                                  tyinfo->rolname, false,
8978                                  "TYPE", SECTION_PRE_DATA,
8979                                  q->data, delq->data, NULL,
8980                                  NULL, 0,
8981                                  NULL, NULL);
8982
8983
8984         /* Dump Type Comments and Security Labels */
8985         dumpComment(fout, labelq->data,
8986                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8987                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8988         dumpSecLabel(fout, labelq->data,
8989                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8990                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8991
8992         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8993                         qtypname, NULL, tyinfo->dobj.name,
8994                         tyinfo->dobj.namespace->dobj.name,
8995                         tyinfo->rolname, tyinfo->typacl);
8996
8997         PQclear(res);
8998         destroyPQExpBuffer(q);
8999         destroyPQExpBuffer(dropped);
9000         destroyPQExpBuffer(delq);
9001         destroyPQExpBuffer(labelq);
9002         destroyPQExpBuffer(query);
9003
9004         /* Dump any per-column comments */
9005         dumpCompositeTypeColComments(fout, tyinfo);
9006 }
9007
9008 /*
9009  * dumpCompositeTypeColComments
9010  *        writes out to fout the queries to recreate comments on the columns of
9011  *        a user-defined stand-alone composite type
9012  */
9013 static void
9014 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9015 {
9016         CommentItem *comments;
9017         int                     ncomments;
9018         PGresult   *res;
9019         PQExpBuffer query;
9020         PQExpBuffer target;
9021         Oid                     pgClassOid;
9022         int                     i;
9023         int                     ntups;
9024         int                     i_attname;
9025         int                     i_attnum;
9026
9027         query = createPQExpBuffer();
9028
9029         /* We assume here that remoteVersion must be at least 70300 */
9030         appendPQExpBuffer(query,
9031                                           "SELECT c.tableoid, a.attname, a.attnum "
9032                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9033                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9034                                           "  AND NOT a.attisdropped "
9035                                           "ORDER BY a.attnum ",
9036                                           tyinfo->typrelid);
9037
9038         /* Fetch column attnames */
9039         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9040
9041         ntups = PQntuples(res);
9042         if (ntups < 1)
9043         {
9044                 PQclear(res);
9045                 destroyPQExpBuffer(query);
9046                 return;
9047         }
9048
9049         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9050
9051         /* Search for comments associated with type's pg_class OID */
9052         ncomments = findComments(fout,
9053                                                          pgClassOid,
9054                                                          tyinfo->typrelid,
9055                                                          &comments);
9056
9057         /* If no comments exist, we're done */
9058         if (ncomments <= 0)
9059         {
9060                 PQclear(res);
9061                 destroyPQExpBuffer(query);
9062                 return;
9063         }
9064
9065         /* Build COMMENT ON statements */
9066         target = createPQExpBuffer();
9067
9068         i_attnum = PQfnumber(res, "attnum");
9069         i_attname = PQfnumber(res, "attname");
9070         while (ncomments > 0)
9071         {
9072                 const char *attname;
9073
9074                 attname = NULL;
9075                 for (i = 0; i < ntups; i++)
9076                 {
9077                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9078                         {
9079                                 attname = PQgetvalue(res, i, i_attname);
9080                                 break;
9081                         }
9082                 }
9083                 if (attname)                    /* just in case we don't find it */
9084                 {
9085                         const char *descr = comments->descr;
9086
9087                         resetPQExpBuffer(target);
9088                         appendPQExpBuffer(target, "COLUMN %s.",
9089                                                           fmtId(tyinfo->dobj.name));
9090                         appendPQExpBuffer(target, "%s",
9091                                                           fmtId(attname));
9092
9093                         resetPQExpBuffer(query);
9094                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9095                         appendStringLiteralAH(query, descr, fout);
9096                         appendPQExpBuffer(query, ";\n");
9097
9098                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9099                                                  target->data,
9100                                                  tyinfo->dobj.namespace->dobj.name,
9101                                                  NULL, tyinfo->rolname,
9102                                                  false, "COMMENT", SECTION_NONE,
9103                                                  query->data, "", NULL,
9104                                                  &(tyinfo->dobj.dumpId), 1,
9105                                                  NULL, NULL);
9106                 }
9107
9108                 comments++;
9109                 ncomments--;
9110         }
9111
9112         PQclear(res);
9113         destroyPQExpBuffer(query);
9114         destroyPQExpBuffer(target);
9115 }
9116
9117 /*
9118  * dumpShellType
9119  *        writes out to fout the queries to create a shell type
9120  *
9121  * We dump a shell definition in advance of the I/O functions for the type.
9122  */
9123 static void
9124 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
9125 {
9126         PQExpBuffer q;
9127
9128         /* Skip if not to be dumped */
9129         if (!stinfo->dobj.dump || dataOnly)
9130                 return;
9131
9132         q = createPQExpBuffer();
9133
9134         /*
9135          * Note the lack of a DROP command for the shell type; any required DROP
9136          * is driven off the base type entry, instead.  This interacts with
9137          * _printTocEntry()'s use of the presence of a DROP command to decide
9138          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9139          * the shell type's owner immediately on creation; that should happen only
9140          * after it's filled in, otherwise the backend complains.
9141          */
9142
9143         if (binary_upgrade)
9144                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9145                                                                                    stinfo->baseType->dobj.catId.oid);
9146
9147         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9148                                           fmtId(stinfo->dobj.name));
9149
9150         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9151                                  stinfo->dobj.name,
9152                                  stinfo->dobj.namespace->dobj.name,
9153                                  NULL,
9154                                  stinfo->baseType->rolname, false,
9155                                  "SHELL TYPE", SECTION_PRE_DATA,
9156                                  q->data, "", NULL,
9157                                  NULL, 0,
9158                                  NULL, NULL);
9159
9160         destroyPQExpBuffer(q);
9161 }
9162
9163 /*
9164  * Determine whether we want to dump definitions for procedural languages.
9165  * Since the languages themselves don't have schemas, we can't rely on
9166  * the normal schema-based selection mechanism.  We choose to dump them
9167  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9168  * the dump flag of the PL's call handler function, but in 8.1 this will
9169  * probably always be false since call handlers are created in pg_catalog.)
9170  *
9171  * For some backwards compatibility with the older behavior, we forcibly
9172  * dump a PL if its handler function (and validator if any) are in a
9173  * dumpable namespace.  That case is not checked here.
9174  *
9175  * Also, if the PL belongs to an extension, we do not use this heuristic.
9176  * That case isn't checked here either.
9177  */
9178 static bool
9179 shouldDumpProcLangs(void)
9180 {
9181         if (!include_everything)
9182                 return false;
9183         /* And they're schema not data */
9184         if (dataOnly)
9185                 return false;
9186         return true;
9187 }
9188
9189 /*
9190  * dumpProcLang
9191  *                writes out to fout the queries to recreate a user-defined
9192  *                procedural language
9193  */
9194 static void
9195 dumpProcLang(Archive *fout, ProcLangInfo *plang)
9196 {
9197         PQExpBuffer defqry;
9198         PQExpBuffer delqry;
9199         PQExpBuffer labelq;
9200         bool            useParams;
9201         char       *qlanname;
9202         char       *lanschema;
9203         FuncInfo   *funcInfo;
9204         FuncInfo   *inlineInfo = NULL;
9205         FuncInfo   *validatorInfo = NULL;
9206
9207         /* Skip if not to be dumped */
9208         if (!plang->dobj.dump || dataOnly)
9209                 return;
9210
9211         /*
9212          * Try to find the support function(s).  It is not an error if we don't
9213          * find them --- if the functions are in the pg_catalog schema, as is
9214          * standard in 8.1 and up, then we won't have loaded them. (In this case
9215          * we will emit a parameterless CREATE LANGUAGE command, which will
9216          * require PL template knowledge in the backend to reload.)
9217          */
9218
9219         funcInfo = findFuncByOid(plang->lanplcallfoid);
9220         if (funcInfo != NULL && !funcInfo->dobj.dump)
9221                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9222
9223         if (OidIsValid(plang->laninline))
9224         {
9225                 inlineInfo = findFuncByOid(plang->laninline);
9226                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9227                         inlineInfo = NULL;
9228         }
9229
9230         if (OidIsValid(plang->lanvalidator))
9231         {
9232                 validatorInfo = findFuncByOid(plang->lanvalidator);
9233                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9234                         validatorInfo = NULL;
9235         }
9236
9237         /*
9238          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9239          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9240          * dump it.
9241          *
9242          * However, for a language that belongs to an extension, we must not use
9243          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9244          * told to (via dobj.dump).  Generally the support functions will belong
9245          * to the same extension and so have the same dump flags ... if they
9246          * don't, this might not work terribly nicely.
9247          */
9248         useParams = (funcInfo != NULL &&
9249                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9250                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9251
9252         if (!plang->dobj.ext_member)
9253         {
9254                 if (!useParams && !shouldDumpProcLangs())
9255                         return;
9256         }
9257
9258         defqry = createPQExpBuffer();
9259         delqry = createPQExpBuffer();
9260         labelq = createPQExpBuffer();
9261
9262         qlanname = pg_strdup(fmtId(plang->dobj.name));
9263
9264         /*
9265          * If dumping a HANDLER clause, treat the language as being in the handler
9266          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9267          * it doesn't really have a schema.
9268          */
9269         if (useParams)
9270                 lanschema = funcInfo->dobj.namespace->dobj.name;
9271         else
9272                 lanschema = NULL;
9273
9274         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9275                                           qlanname);
9276
9277         if (useParams)
9278         {
9279                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9280                                                   plang->lanpltrusted ? "TRUSTED " : "",
9281                                                   qlanname);
9282                 appendPQExpBuffer(defqry, " HANDLER %s",
9283                                                   fmtId(funcInfo->dobj.name));
9284                 if (OidIsValid(plang->laninline))
9285                 {
9286                         appendPQExpBuffer(defqry, " INLINE ");
9287                         /* Cope with possibility that inline is in different schema */
9288                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9289                                 appendPQExpBuffer(defqry, "%s.",
9290                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9291                         appendPQExpBuffer(defqry, "%s",
9292                                                           fmtId(inlineInfo->dobj.name));
9293                 }
9294                 if (OidIsValid(plang->lanvalidator))
9295                 {
9296                         appendPQExpBuffer(defqry, " VALIDATOR ");
9297                         /* Cope with possibility that validator is in different schema */
9298                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9299                                 appendPQExpBuffer(defqry, "%s.",
9300                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9301                         appendPQExpBuffer(defqry, "%s",
9302                                                           fmtId(validatorInfo->dobj.name));
9303                 }
9304         }
9305         else
9306         {
9307                 /*
9308                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9309                  * command will not fail if the language is preinstalled in the target
9310                  * database.  We restrict the use of REPLACE to this case so as to
9311                  * eliminate the risk of replacing a language with incompatible
9312                  * parameter settings: this command will only succeed at all if there
9313                  * is a pg_pltemplate entry, and if there is one, the existing entry
9314                  * must match it too.
9315                  */
9316                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9317                                                   qlanname);
9318         }
9319         appendPQExpBuffer(defqry, ";\n");
9320
9321         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9322
9323         if (binary_upgrade)
9324                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9325
9326         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9327                                  plang->dobj.name,
9328                                  lanschema, NULL, plang->lanowner,
9329                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9330                                  defqry->data, delqry->data, NULL,
9331                                  NULL, 0,
9332                                  NULL, NULL);
9333
9334         /* Dump Proc Lang Comments and Security Labels */
9335         dumpComment(fout, labelq->data,
9336                                 NULL, "",
9337                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9338         dumpSecLabel(fout, labelq->data,
9339                                  NULL, "",
9340                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9341
9342         if (plang->lanpltrusted)
9343                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9344                                 qlanname, NULL, plang->dobj.name,
9345                                 lanschema,
9346                                 plang->lanowner, plang->lanacl);
9347
9348         free(qlanname);
9349
9350         destroyPQExpBuffer(defqry);
9351         destroyPQExpBuffer(delqry);
9352         destroyPQExpBuffer(labelq);
9353 }
9354
9355 /*
9356  * format_function_arguments: generate function name and argument list
9357  *
9358  * This is used when we can rely on pg_get_function_arguments to format
9359  * the argument list.
9360  */
9361 static char *
9362 format_function_arguments(FuncInfo *finfo, char *funcargs)
9363 {
9364         PQExpBufferData fn;
9365
9366         initPQExpBuffer(&fn);
9367         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
9368         return fn.data;
9369 }
9370
9371 /*
9372  * format_function_arguments_old: generate function name and argument list
9373  *
9374  * The argument type names are qualified if needed.  The function name
9375  * is never qualified.
9376  *
9377  * This is used only with pre-8.4 servers, so we aren't expecting to see
9378  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9379  *
9380  * Any or all of allargtypes, argmodes, argnames may be NULL.
9381  */
9382 static char *
9383 format_function_arguments_old(Archive *fout,
9384                                                           FuncInfo *finfo, int nallargs,
9385                                                           char **allargtypes,
9386                                                           char **argmodes,
9387                                                           char **argnames)
9388 {
9389         PQExpBufferData fn;
9390         int                     j;
9391
9392         initPQExpBuffer(&fn);
9393         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9394         for (j = 0; j < nallargs; j++)
9395         {
9396                 Oid                     typid;
9397                 char       *typname;
9398                 const char *argmode;
9399                 const char *argname;
9400
9401                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9402                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9403
9404                 if (argmodes)
9405                 {
9406                         switch (argmodes[j][0])
9407                         {
9408                                 case PROARGMODE_IN:
9409                                         argmode = "";
9410                                         break;
9411                                 case PROARGMODE_OUT:
9412                                         argmode = "OUT ";
9413                                         break;
9414                                 case PROARGMODE_INOUT:
9415                                         argmode = "INOUT ";
9416                                         break;
9417                                 default:
9418                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9419                                         argmode = "";
9420                                         break;
9421                         }
9422                 }
9423                 else
9424                         argmode = "";
9425
9426                 argname = argnames ? argnames[j] : (char *) NULL;
9427                 if (argname && argname[0] == '\0')
9428                         argname = NULL;
9429
9430                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9431                                                   (j > 0) ? ", " : "",
9432                                                   argmode,
9433                                                   argname ? fmtId(argname) : "",
9434                                                   argname ? " " : "",
9435                                                   typname);
9436                 free(typname);
9437         }
9438         appendPQExpBuffer(&fn, ")");
9439         return fn.data;
9440 }
9441
9442 /*
9443  * format_function_signature: generate function name and argument list
9444  *
9445  * This is like format_function_arguments_old except that only a minimal
9446  * list of input argument types is generated; this is sufficient to
9447  * reference the function, but not to define it.
9448  *
9449  * If honor_quotes is false then the function name is never quoted.
9450  * This is appropriate for use in TOC tags, but not in SQL commands.
9451  */
9452 static char *
9453 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9454 {
9455         PQExpBufferData fn;
9456         int                     j;
9457
9458         initPQExpBuffer(&fn);
9459         if (honor_quotes)
9460                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9461         else
9462                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9463         for (j = 0; j < finfo->nargs; j++)
9464         {
9465                 char       *typname;
9466
9467                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9468                                                                            zeroAsOpaque);
9469
9470                 appendPQExpBuffer(&fn, "%s%s",
9471                                                   (j > 0) ? ", " : "",
9472                                                   typname);
9473                 free(typname);
9474         }
9475         appendPQExpBuffer(&fn, ")");
9476         return fn.data;
9477 }
9478
9479
9480 /*
9481  * dumpFunc:
9482  *        dump out one function
9483  */
9484 static void
9485 dumpFunc(Archive *fout, FuncInfo *finfo)
9486 {
9487         PQExpBuffer query;
9488         PQExpBuffer q;
9489         PQExpBuffer delqry;
9490         PQExpBuffer labelq;
9491         PQExpBuffer asPart;
9492         PGresult   *res;
9493         char       *funcsig;            /* identity signature */
9494         char       *funcfullsig;        /* full signature */
9495         char       *funcsig_tag;
9496         char       *proretset;
9497         char       *prosrc;
9498         char       *probin;
9499         char       *funcargs;
9500         char       *funciargs;
9501         char       *funcresult;
9502         char       *proallargtypes;
9503         char       *proargmodes;
9504         char       *proargnames;
9505         char       *proiswindow;
9506         char       *provolatile;
9507         char       *proisstrict;
9508         char       *prosecdef;
9509         char       *proleakproof;
9510         char       *proconfig;
9511         char       *procost;
9512         char       *prorows;
9513         char       *lanname;
9514         char       *rettypename;
9515         int                     nallargs;
9516         char      **allargtypes = NULL;
9517         char      **argmodes = NULL;
9518         char      **argnames = NULL;
9519         char      **configitems = NULL;
9520         int                     nconfigitems = 0;
9521         int                     i;
9522
9523         /* Skip if not to be dumped */
9524         if (!finfo->dobj.dump || dataOnly)
9525                 return;
9526
9527         query = createPQExpBuffer();
9528         q = createPQExpBuffer();
9529         delqry = createPQExpBuffer();
9530         labelq = createPQExpBuffer();
9531         asPart = createPQExpBuffer();
9532
9533         /* Set proper schema search path so type references list correctly */
9534         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9535
9536         /* Fetch function-specific details */
9537         if (fout->remoteVersion >= 90200)
9538         {
9539                 /*
9540                  * proleakproof was added at v9.2
9541                  */
9542                 appendPQExpBuffer(query,
9543                                                   "SELECT proretset, prosrc, probin, "
9544                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9545                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9546                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9547                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9548                                                   "proleakproof, proconfig, procost, prorows, "
9549                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9550                                                   "FROM pg_catalog.pg_proc "
9551                                                   "WHERE oid = '%u'::pg_catalog.oid",
9552                                                   finfo->dobj.catId.oid);
9553         }
9554         else if (fout->remoteVersion >= 80400)
9555         {
9556                 /*
9557                  * In 8.4 and up we rely on pg_get_function_arguments and
9558                  * pg_get_function_result instead of examining proallargtypes etc.
9559                  */
9560                 appendPQExpBuffer(query,
9561                                                   "SELECT proretset, prosrc, probin, "
9562                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9563                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9564                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9565                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9566                                                   "false AS proleakproof, "
9567                                                   " proconfig, procost, prorows, "
9568                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9569                                                   "FROM pg_catalog.pg_proc "
9570                                                   "WHERE oid = '%u'::pg_catalog.oid",
9571                                                   finfo->dobj.catId.oid);
9572         }
9573         else if (fout->remoteVersion >= 80300)
9574         {
9575                 appendPQExpBuffer(query,
9576                                                   "SELECT proretset, prosrc, probin, "
9577                                                   "proallargtypes, proargmodes, proargnames, "
9578                                                   "false AS proiswindow, "
9579                                                   "provolatile, proisstrict, prosecdef, "
9580                                                   "false AS proleakproof, "
9581                                                   "proconfig, procost, prorows, "
9582                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9583                                                   "FROM pg_catalog.pg_proc "
9584                                                   "WHERE oid = '%u'::pg_catalog.oid",
9585                                                   finfo->dobj.catId.oid);
9586         }
9587         else if (fout->remoteVersion >= 80100)
9588         {
9589                 appendPQExpBuffer(query,
9590                                                   "SELECT proretset, prosrc, probin, "
9591                                                   "proallargtypes, proargmodes, proargnames, "
9592                                                   "false AS proiswindow, "
9593                                                   "provolatile, proisstrict, prosecdef, "
9594                                                   "false AS proleakproof, "
9595                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9596                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9597                                                   "FROM pg_catalog.pg_proc "
9598                                                   "WHERE oid = '%u'::pg_catalog.oid",
9599                                                   finfo->dobj.catId.oid);
9600         }
9601         else if (fout->remoteVersion >= 80000)
9602         {
9603                 appendPQExpBuffer(query,
9604                                                   "SELECT proretset, prosrc, probin, "
9605                                                   "null AS proallargtypes, "
9606                                                   "null AS proargmodes, "
9607                                                   "proargnames, "
9608                                                   "false AS proiswindow, "
9609                                                   "provolatile, proisstrict, prosecdef, "
9610                                                   "false AS proleakproof, "
9611                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9612                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9613                                                   "FROM pg_catalog.pg_proc "
9614                                                   "WHERE oid = '%u'::pg_catalog.oid",
9615                                                   finfo->dobj.catId.oid);
9616         }
9617         else if (fout->remoteVersion >= 70300)
9618         {
9619                 appendPQExpBuffer(query,
9620                                                   "SELECT proretset, prosrc, probin, "
9621                                                   "null AS proallargtypes, "
9622                                                   "null AS proargmodes, "
9623                                                   "null AS proargnames, "
9624                                                   "false AS proiswindow, "
9625                                                   "provolatile, proisstrict, prosecdef, "
9626                                                   "false AS proleakproof, "
9627                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9628                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9629                                                   "FROM pg_catalog.pg_proc "
9630                                                   "WHERE oid = '%u'::pg_catalog.oid",
9631                                                   finfo->dobj.catId.oid);
9632         }
9633         else if (fout->remoteVersion >= 70100)
9634         {
9635                 appendPQExpBuffer(query,
9636                                                   "SELECT proretset, prosrc, probin, "
9637                                                   "null AS proallargtypes, "
9638                                                   "null AS proargmodes, "
9639                                                   "null AS proargnames, "
9640                                                   "false AS proiswindow, "
9641                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9642                                                   "proisstrict, "
9643                                                   "false AS prosecdef, "
9644                                                   "false AS proleakproof, "
9645                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9646                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9647                                                   "FROM pg_proc "
9648                                                   "WHERE oid = '%u'::oid",
9649                                                   finfo->dobj.catId.oid);
9650         }
9651         else
9652         {
9653                 appendPQExpBuffer(query,
9654                                                   "SELECT proretset, prosrc, probin, "
9655                                                   "null AS proallargtypes, "
9656                                                   "null AS proargmodes, "
9657                                                   "null AS proargnames, "
9658                                                   "false AS proiswindow, "
9659                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9660                                                   "false AS proisstrict, "
9661                                                   "false AS prosecdef, "
9662                                                   "false AS proleakproof, "
9663                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9664                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9665                                                   "FROM pg_proc "
9666                                                   "WHERE oid = '%u'::oid",
9667                                                   finfo->dobj.catId.oid);
9668         }
9669
9670         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9671
9672         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9673         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9674         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9675         if (fout->remoteVersion >= 80400)
9676         {
9677                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9678                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9679                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9680                 proallargtypes = proargmodes = proargnames = NULL;
9681         }
9682         else
9683         {
9684                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9685                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9686                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9687                 funcargs = funciargs = funcresult = NULL;
9688         }
9689         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9690         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9691         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9692         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9693         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9694         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9695         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9696         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9697         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9698
9699         /*
9700          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9701          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9702          * versions would set it to "-".  There are no known cases in which prosrc
9703          * is unused, so the tests below for "-" are probably useless.
9704          */
9705         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9706         {
9707                 appendPQExpBuffer(asPart, "AS ");
9708                 appendStringLiteralAH(asPart, probin, fout);
9709                 if (strcmp(prosrc, "-") != 0)
9710                 {
9711                         appendPQExpBuffer(asPart, ", ");
9712
9713                         /*
9714                          * where we have bin, use dollar quoting if allowed and src
9715                          * contains quote or backslash; else use regular quoting.
9716                          */
9717                         if (disable_dollar_quoting ||
9718                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9719                                 appendStringLiteralAH(asPart, prosrc, fout);
9720                         else
9721                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9722                 }
9723         }
9724         else
9725         {
9726                 if (strcmp(prosrc, "-") != 0)
9727                 {
9728                         appendPQExpBuffer(asPart, "AS ");
9729                         /* with no bin, dollar quote src unconditionally if allowed */
9730                         if (disable_dollar_quoting)
9731                                 appendStringLiteralAH(asPart, prosrc, fout);
9732                         else
9733                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9734                 }
9735         }
9736
9737         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9738
9739         if (proallargtypes && *proallargtypes)
9740         {
9741                 int                     nitems = 0;
9742
9743                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9744                         nitems < finfo->nargs)
9745                 {
9746                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9747                         if (allargtypes)
9748                                 free(allargtypes);
9749                         allargtypes = NULL;
9750                 }
9751                 else
9752                         nallargs = nitems;
9753         }
9754
9755         if (proargmodes && *proargmodes)
9756         {
9757                 int                     nitems = 0;
9758
9759                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9760                         nitems != nallargs)
9761                 {
9762                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9763                         if (argmodes)
9764                                 free(argmodes);
9765                         argmodes = NULL;
9766                 }
9767         }
9768
9769         if (proargnames && *proargnames)
9770         {
9771                 int                     nitems = 0;
9772
9773                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9774                         nitems != nallargs)
9775                 {
9776                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9777                         if (argnames)
9778                                 free(argnames);
9779                         argnames = NULL;
9780                 }
9781         }
9782
9783         if (proconfig && *proconfig)
9784         {
9785                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9786                 {
9787                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9788                         if (configitems)
9789                                 free(configitems);
9790                         configitems = NULL;
9791                         nconfigitems = 0;
9792                 }
9793         }
9794
9795         if (funcargs)
9796         {
9797                 /* 8.4 or later; we rely on server-side code for most of the work */
9798                 funcfullsig = format_function_arguments(finfo, funcargs);
9799                 funcsig = format_function_arguments(finfo, funciargs);
9800         }
9801         else
9802         {
9803                 /* pre-8.4, do it ourselves */
9804                 funcsig = format_function_arguments_old(fout,
9805                                                                                                 finfo, nallargs, allargtypes,
9806                                                                                                 argmodes, argnames);
9807                 funcfullsig = funcsig;
9808         }
9809
9810         funcsig_tag = format_function_signature(fout, finfo, false);
9811
9812         /*
9813          * DROP must be fully qualified in case same name appears in pg_catalog
9814          */
9815         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9816                                           fmtId(finfo->dobj.namespace->dobj.name),
9817                                           funcsig);
9818
9819         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9820         if (funcresult)
9821                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9822         else
9823         {
9824                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9825                                                                                    zeroAsOpaque);
9826                 appendPQExpBuffer(q, "RETURNS %s%s",
9827                                                   (proretset[0] == 't') ? "SETOF " : "",
9828                                                   rettypename);
9829                 free(rettypename);
9830         }
9831
9832         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9833
9834         if (proiswindow[0] == 't')
9835                 appendPQExpBuffer(q, " WINDOW");
9836
9837         if (provolatile[0] != PROVOLATILE_VOLATILE)
9838         {
9839                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9840                         appendPQExpBuffer(q, " IMMUTABLE");
9841                 else if (provolatile[0] == PROVOLATILE_STABLE)
9842                         appendPQExpBuffer(q, " STABLE");
9843                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9844                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9845                                                   finfo->dobj.name);
9846         }
9847
9848         if (proisstrict[0] == 't')
9849                 appendPQExpBuffer(q, " STRICT");
9850
9851         if (prosecdef[0] == 't')
9852                 appendPQExpBuffer(q, " SECURITY DEFINER");
9853
9854         if (proleakproof[0] == 't')
9855                 appendPQExpBuffer(q, " LEAKPROOF");
9856
9857         /*
9858          * COST and ROWS are emitted only if present and not default, so as not to
9859          * break backwards-compatibility of the dump without need.      Keep this code
9860          * in sync with the defaults in functioncmds.c.
9861          */
9862         if (strcmp(procost, "0") != 0)
9863         {
9864                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9865                 {
9866                         /* default cost is 1 */
9867                         if (strcmp(procost, "1") != 0)
9868                                 appendPQExpBuffer(q, " COST %s", procost);
9869                 }
9870                 else
9871                 {
9872                         /* default cost is 100 */
9873                         if (strcmp(procost, "100") != 0)
9874                                 appendPQExpBuffer(q, " COST %s", procost);
9875                 }
9876         }
9877         if (proretset[0] == 't' &&
9878                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9879                 appendPQExpBuffer(q, " ROWS %s", prorows);
9880
9881         for (i = 0; i < nconfigitems; i++)
9882         {
9883                 /* we feel free to scribble on configitems[] here */
9884                 char       *configitem = configitems[i];
9885                 char       *pos;
9886
9887                 pos = strchr(configitem, '=');
9888                 if (pos == NULL)
9889                         continue;
9890                 *pos++ = '\0';
9891                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9892
9893                 /*
9894                  * Some GUC variable names are 'LIST' type and hence must not be
9895                  * quoted.
9896                  */
9897                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9898                         || pg_strcasecmp(configitem, "search_path") == 0)
9899                         appendPQExpBuffer(q, "%s", pos);
9900                 else
9901                         appendStringLiteralAH(q, pos, fout);
9902         }
9903
9904         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9905
9906         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9907
9908         if (binary_upgrade)
9909                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9910
9911         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9912                                  funcsig_tag,
9913                                  finfo->dobj.namespace->dobj.name,
9914                                  NULL,
9915                                  finfo->rolname, false,
9916                                  "FUNCTION", SECTION_PRE_DATA,
9917                                  q->data, delqry->data, NULL,
9918                                  NULL, 0,
9919                                  NULL, NULL);
9920
9921         /* Dump Function Comments and Security Labels */
9922         dumpComment(fout, labelq->data,
9923                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9924                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9925         dumpSecLabel(fout, labelq->data,
9926                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9927                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9928
9929         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9930                         funcsig, NULL, funcsig_tag,
9931                         finfo->dobj.namespace->dobj.name,
9932                         finfo->rolname, finfo->proacl);
9933
9934         PQclear(res);
9935
9936         destroyPQExpBuffer(query);
9937         destroyPQExpBuffer(q);
9938         destroyPQExpBuffer(delqry);
9939         destroyPQExpBuffer(labelq);
9940         destroyPQExpBuffer(asPart);
9941         free(funcsig);
9942         free(funcsig_tag);
9943         if (allargtypes)
9944                 free(allargtypes);
9945         if (argmodes)
9946                 free(argmodes);
9947         if (argnames)
9948                 free(argnames);
9949         if (configitems)
9950                 free(configitems);
9951 }
9952
9953
9954 /*
9955  * Dump a user-defined cast
9956  */
9957 static void
9958 dumpCast(Archive *fout, CastInfo *cast)
9959 {
9960         PQExpBuffer defqry;
9961         PQExpBuffer delqry;
9962         PQExpBuffer labelq;
9963         FuncInfo   *funcInfo = NULL;
9964
9965         /* Skip if not to be dumped */
9966         if (!cast->dobj.dump || dataOnly)
9967                 return;
9968
9969         /* Cannot dump if we don't have the cast function's info */
9970         if (OidIsValid(cast->castfunc))
9971         {
9972                 funcInfo = findFuncByOid(cast->castfunc);
9973                 if (funcInfo == NULL)
9974                         return;
9975         }
9976
9977         /*
9978          * As per discussion we dump casts if one or more of the underlying
9979          * objects (the conversion function and the two data types) are not
9980          * builtin AND if all of the non-builtin objects are included in the dump.
9981          * Builtin meaning, the namespace name does not start with "pg_".
9982          *
9983          * However, for a cast that belongs to an extension, we must not use this
9984          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
9985          */
9986         if (!cast->dobj.ext_member)
9987         {
9988                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
9989                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
9990
9991                 if (sourceInfo == NULL || targetInfo == NULL)
9992                         return;
9993
9994                 /*
9995                  * Skip this cast if all objects are from pg_
9996                  */
9997                 if ((funcInfo == NULL ||
9998                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
9999                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10000                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10001                         return;
10002
10003                 /*
10004                  * Skip cast if function isn't from pg_ and is not to be dumped.
10005                  */
10006                 if (funcInfo &&
10007                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10008                         !funcInfo->dobj.dump)
10009                         return;
10010
10011                 /*
10012                  * Same for the source type
10013                  */
10014                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10015                         !sourceInfo->dobj.dump)
10016                         return;
10017
10018                 /*
10019                  * and the target type.
10020                  */
10021                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10022                         !targetInfo->dobj.dump)
10023                         return;
10024         }
10025
10026         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10027         selectSourceSchema(fout, "pg_catalog");
10028
10029         defqry = createPQExpBuffer();
10030         delqry = createPQExpBuffer();
10031         labelq = createPQExpBuffer();
10032
10033         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10034                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10035                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10036
10037         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10038                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10039                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10040
10041         switch (cast->castmethod)
10042         {
10043                 case COERCION_METHOD_BINARY:
10044                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
10045                         break;
10046                 case COERCION_METHOD_INOUT:
10047                         appendPQExpBuffer(defqry, "WITH INOUT");
10048                         break;
10049                 case COERCION_METHOD_FUNCTION:
10050                         if (funcInfo)
10051                         {
10052                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10053
10054                                 /*
10055                                  * Always qualify the function name, in case it is not in
10056                                  * pg_catalog schema (format_function_signature won't qualify
10057                                  * it).
10058                                  */
10059                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10060                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10061                                 free(fsig);
10062                         }
10063                         else
10064                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10065                         break;
10066                 default:
10067                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10068         }
10069
10070         if (cast->castcontext == 'a')
10071                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
10072         else if (cast->castcontext == 'i')
10073                 appendPQExpBuffer(defqry, " AS IMPLICIT");
10074         appendPQExpBuffer(defqry, ";\n");
10075
10076         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10077                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10078                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10079
10080         if (binary_upgrade)
10081                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10082
10083         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10084                                  labelq->data,
10085                                  "pg_catalog", NULL, "",
10086                                  false, "CAST", SECTION_PRE_DATA,
10087                                  defqry->data, delqry->data, NULL,
10088                                  NULL, 0,
10089                                  NULL, NULL);
10090
10091         /* Dump Cast Comments */
10092         dumpComment(fout, labelq->data,
10093                                 NULL, "",
10094                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10095
10096         destroyPQExpBuffer(defqry);
10097         destroyPQExpBuffer(delqry);
10098         destroyPQExpBuffer(labelq);
10099 }
10100
10101 /*
10102  * dumpOpr
10103  *        write out a single operator definition
10104  */
10105 static void
10106 dumpOpr(Archive *fout, OprInfo *oprinfo)
10107 {
10108         PQExpBuffer query;
10109         PQExpBuffer q;
10110         PQExpBuffer delq;
10111         PQExpBuffer labelq;
10112         PQExpBuffer oprid;
10113         PQExpBuffer details;
10114         const char *name;
10115         PGresult   *res;
10116         int                     i_oprkind;
10117         int                     i_oprcode;
10118         int                     i_oprleft;
10119         int                     i_oprright;
10120         int                     i_oprcom;
10121         int                     i_oprnegate;
10122         int                     i_oprrest;
10123         int                     i_oprjoin;
10124         int                     i_oprcanmerge;
10125         int                     i_oprcanhash;
10126         char       *oprkind;
10127         char       *oprcode;
10128         char       *oprleft;
10129         char       *oprright;
10130         char       *oprcom;
10131         char       *oprnegate;
10132         char       *oprrest;
10133         char       *oprjoin;
10134         char       *oprcanmerge;
10135         char       *oprcanhash;
10136
10137         /* Skip if not to be dumped */
10138         if (!oprinfo->dobj.dump || dataOnly)
10139                 return;
10140
10141         /*
10142          * some operators are invalid because they were the result of user
10143          * defining operators before commutators exist
10144          */
10145         if (!OidIsValid(oprinfo->oprcode))
10146                 return;
10147
10148         query = createPQExpBuffer();
10149         q = createPQExpBuffer();
10150         delq = createPQExpBuffer();
10151         labelq = createPQExpBuffer();
10152         oprid = createPQExpBuffer();
10153         details = createPQExpBuffer();
10154
10155         /* Make sure we are in proper schema so regoperator works correctly */
10156         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10157
10158         if (fout->remoteVersion >= 80300)
10159         {
10160                 appendPQExpBuffer(query, "SELECT oprkind, "
10161                                                   "oprcode::pg_catalog.regprocedure, "
10162                                                   "oprleft::pg_catalog.regtype, "
10163                                                   "oprright::pg_catalog.regtype, "
10164                                                   "oprcom::pg_catalog.regoperator, "
10165                                                   "oprnegate::pg_catalog.regoperator, "
10166                                                   "oprrest::pg_catalog.regprocedure, "
10167                                                   "oprjoin::pg_catalog.regprocedure, "
10168                                                   "oprcanmerge, oprcanhash "
10169                                                   "FROM pg_catalog.pg_operator "
10170                                                   "WHERE oid = '%u'::pg_catalog.oid",
10171                                                   oprinfo->dobj.catId.oid);
10172         }
10173         else if (fout->remoteVersion >= 70300)
10174         {
10175                 appendPQExpBuffer(query, "SELECT oprkind, "
10176                                                   "oprcode::pg_catalog.regprocedure, "
10177                                                   "oprleft::pg_catalog.regtype, "
10178                                                   "oprright::pg_catalog.regtype, "
10179                                                   "oprcom::pg_catalog.regoperator, "
10180                                                   "oprnegate::pg_catalog.regoperator, "
10181                                                   "oprrest::pg_catalog.regprocedure, "
10182                                                   "oprjoin::pg_catalog.regprocedure, "
10183                                                   "(oprlsortop != 0) AS oprcanmerge, "
10184                                                   "oprcanhash "
10185                                                   "FROM pg_catalog.pg_operator "
10186                                                   "WHERE oid = '%u'::pg_catalog.oid",
10187                                                   oprinfo->dobj.catId.oid);
10188         }
10189         else if (fout->remoteVersion >= 70100)
10190         {
10191                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10192                                                   "CASE WHEN oprleft = 0 THEN '-' "
10193                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10194                                                   "CASE WHEN oprright = 0 THEN '-' "
10195                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10196                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10197                                                   "(oprlsortop != 0) AS oprcanmerge, "
10198                                                   "oprcanhash "
10199                                                   "FROM pg_operator "
10200                                                   "WHERE oid = '%u'::oid",
10201                                                   oprinfo->dobj.catId.oid);
10202         }
10203         else
10204         {
10205                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10206                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10207                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10208                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10209                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10210                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10211                                                   "(oprlsortop != 0) AS oprcanmerge, "
10212                                                   "oprcanhash "
10213                                                   "FROM pg_operator "
10214                                                   "WHERE oid = '%u'::oid",
10215                                                   oprinfo->dobj.catId.oid);
10216         }
10217
10218         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10219
10220         i_oprkind = PQfnumber(res, "oprkind");
10221         i_oprcode = PQfnumber(res, "oprcode");
10222         i_oprleft = PQfnumber(res, "oprleft");
10223         i_oprright = PQfnumber(res, "oprright");
10224         i_oprcom = PQfnumber(res, "oprcom");
10225         i_oprnegate = PQfnumber(res, "oprnegate");
10226         i_oprrest = PQfnumber(res, "oprrest");
10227         i_oprjoin = PQfnumber(res, "oprjoin");
10228         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10229         i_oprcanhash = PQfnumber(res, "oprcanhash");
10230
10231         oprkind = PQgetvalue(res, 0, i_oprkind);
10232         oprcode = PQgetvalue(res, 0, i_oprcode);
10233         oprleft = PQgetvalue(res, 0, i_oprleft);
10234         oprright = PQgetvalue(res, 0, i_oprright);
10235         oprcom = PQgetvalue(res, 0, i_oprcom);
10236         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10237         oprrest = PQgetvalue(res, 0, i_oprrest);
10238         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10239         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10240         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10241
10242         appendPQExpBuffer(details, "    PROCEDURE = %s",
10243                                           convertRegProcReference(fout, oprcode));
10244
10245         appendPQExpBuffer(oprid, "%s (",
10246                                           oprinfo->dobj.name);
10247
10248         /*
10249          * right unary means there's a left arg and left unary means there's a
10250          * right arg
10251          */
10252         if (strcmp(oprkind, "r") == 0 ||
10253                 strcmp(oprkind, "b") == 0)
10254         {
10255                 if (fout->remoteVersion >= 70100)
10256                         name = oprleft;
10257                 else
10258                         name = fmtId(oprleft);
10259                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10260                 appendPQExpBuffer(oprid, "%s", name);
10261         }
10262         else
10263                 appendPQExpBuffer(oprid, "NONE");
10264
10265         if (strcmp(oprkind, "l") == 0 ||
10266                 strcmp(oprkind, "b") == 0)
10267         {
10268                 if (fout->remoteVersion >= 70100)
10269                         name = oprright;
10270                 else
10271                         name = fmtId(oprright);
10272                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10273                 appendPQExpBuffer(oprid, ", %s)", name);
10274         }
10275         else
10276                 appendPQExpBuffer(oprid, ", NONE)");
10277
10278         name = convertOperatorReference(fout, oprcom);
10279         if (name)
10280                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
10281
10282         name = convertOperatorReference(fout, oprnegate);
10283         if (name)
10284                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
10285
10286         if (strcmp(oprcanmerge, "t") == 0)
10287                 appendPQExpBuffer(details, ",\n    MERGES");
10288
10289         if (strcmp(oprcanhash, "t") == 0)
10290                 appendPQExpBuffer(details, ",\n    HASHES");
10291
10292         name = convertRegProcReference(fout, oprrest);
10293         if (name)
10294                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
10295
10296         name = convertRegProcReference(fout, oprjoin);
10297         if (name)
10298                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
10299
10300         /*
10301          * DROP must be fully qualified in case same name appears in pg_catalog
10302          */
10303         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10304                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10305                                           oprid->data);
10306
10307         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10308                                           oprinfo->dobj.name, details->data);
10309
10310         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10311
10312         if (binary_upgrade)
10313                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10314
10315         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10316                                  oprinfo->dobj.name,
10317                                  oprinfo->dobj.namespace->dobj.name,
10318                                  NULL,
10319                                  oprinfo->rolname,
10320                                  false, "OPERATOR", SECTION_PRE_DATA,
10321                                  q->data, delq->data, NULL,
10322                                  NULL, 0,
10323                                  NULL, NULL);
10324
10325         /* Dump Operator Comments */
10326         dumpComment(fout, labelq->data,
10327                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10328                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10329
10330         PQclear(res);
10331
10332         destroyPQExpBuffer(query);
10333         destroyPQExpBuffer(q);
10334         destroyPQExpBuffer(delq);
10335         destroyPQExpBuffer(labelq);
10336         destroyPQExpBuffer(oprid);
10337         destroyPQExpBuffer(details);
10338 }
10339
10340 /*
10341  * Convert a function reference obtained from pg_operator
10342  *
10343  * Returns what to print, or NULL if function references is InvalidOid
10344  *
10345  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10346  * argument-types part.  In prior versions, the input is a REGPROC display.
10347  */
10348 static const char *
10349 convertRegProcReference(Archive *fout, const char *proc)
10350 {
10351         /* In all cases "-" means a null reference */
10352         if (strcmp(proc, "-") == 0)
10353                 return NULL;
10354
10355         if (fout->remoteVersion >= 70300)
10356         {
10357                 char       *name;
10358                 char       *paren;
10359                 bool            inquote;
10360
10361                 name = pg_strdup(proc);
10362                 /* find non-double-quoted left paren */
10363                 inquote = false;
10364                 for (paren = name; *paren; paren++)
10365                 {
10366                         if (*paren == '(' && !inquote)
10367                         {
10368                                 *paren = '\0';
10369                                 break;
10370                         }
10371                         if (*paren == '"')
10372                                 inquote = !inquote;
10373                 }
10374                 return name;
10375         }
10376
10377         /* REGPROC before 7.3 does not quote its result */
10378         return fmtId(proc);
10379 }
10380
10381 /*
10382  * Convert an operator cross-reference obtained from pg_operator
10383  *
10384  * Returns what to print, or NULL to print nothing
10385  *
10386  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10387  * argument-types part, and add OPERATOR() decoration if the name is
10388  * schema-qualified.  In older versions, the input is just a numeric OID,
10389  * which we search our operator list for.
10390  */
10391 static const char *
10392 convertOperatorReference(Archive *fout, const char *opr)
10393 {
10394         OprInfo    *oprInfo;
10395
10396         /* In all cases "0" means a null reference */
10397         if (strcmp(opr, "0") == 0)
10398                 return NULL;
10399
10400         if (fout->remoteVersion >= 70300)
10401         {
10402                 char       *name;
10403                 char       *oname;
10404                 char       *ptr;
10405                 bool            inquote;
10406                 bool            sawdot;
10407
10408                 name = pg_strdup(opr);
10409                 /* find non-double-quoted left paren, and check for non-quoted dot */
10410                 inquote = false;
10411                 sawdot = false;
10412                 for (ptr = name; *ptr; ptr++)
10413                 {
10414                         if (*ptr == '"')
10415                                 inquote = !inquote;
10416                         else if (*ptr == '.' && !inquote)
10417                                 sawdot = true;
10418                         else if (*ptr == '(' && !inquote)
10419                         {
10420                                 *ptr = '\0';
10421                                 break;
10422                         }
10423                 }
10424                 /* If not schema-qualified, don't need to add OPERATOR() */
10425                 if (!sawdot)
10426                         return name;
10427                 oname = pg_malloc(strlen(name) + 11);
10428                 sprintf(oname, "OPERATOR(%s)", name);
10429                 free(name);
10430                 return oname;
10431         }
10432
10433         oprInfo = findOprByOid(atooid(opr));
10434         if (oprInfo == NULL)
10435         {
10436                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10437                                   opr);
10438                 return NULL;
10439         }
10440         return oprInfo->dobj.name;
10441 }
10442
10443 /*
10444  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10445  *
10446  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10447  * argument lists of these functions are predetermined.  Note that the
10448  * caller should ensure we are in the proper schema, because the results
10449  * are search path dependent!
10450  */
10451 static const char *
10452 convertTSFunction(Archive *fout, Oid funcOid)
10453 {
10454         char       *result;
10455         char            query[128];
10456         PGresult   *res;
10457
10458         snprintf(query, sizeof(query),
10459                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10460         res = ExecuteSqlQueryForSingleRow(fout, query);
10461
10462         result = pg_strdup(PQgetvalue(res, 0, 0));
10463
10464         PQclear(res);
10465
10466         return result;
10467 }
10468
10469
10470 /*
10471  * dumpOpclass
10472  *        write out a single operator class definition
10473  */
10474 static void
10475 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10476 {
10477         PQExpBuffer query;
10478         PQExpBuffer q;
10479         PQExpBuffer delq;
10480         PQExpBuffer labelq;
10481         PGresult   *res;
10482         int                     ntups;
10483         int                     i_opcintype;
10484         int                     i_opckeytype;
10485         int                     i_opcdefault;
10486         int                     i_opcfamily;
10487         int                     i_opcfamilyname;
10488         int                     i_opcfamilynsp;
10489         int                     i_amname;
10490         int                     i_amopstrategy;
10491         int                     i_amopreqcheck;
10492         int                     i_amopopr;
10493         int                     i_sortfamily;
10494         int                     i_sortfamilynsp;
10495         int                     i_amprocnum;
10496         int                     i_amproc;
10497         int                     i_amproclefttype;
10498         int                     i_amprocrighttype;
10499         char       *opcintype;
10500         char       *opckeytype;
10501         char       *opcdefault;
10502         char       *opcfamily;
10503         char       *opcfamilyname;
10504         char       *opcfamilynsp;
10505         char       *amname;
10506         char       *amopstrategy;
10507         char       *amopreqcheck;
10508         char       *amopopr;
10509         char       *sortfamily;
10510         char       *sortfamilynsp;
10511         char       *amprocnum;
10512         char       *amproc;
10513         char       *amproclefttype;
10514         char       *amprocrighttype;
10515         bool            needComma;
10516         int                     i;
10517
10518         /* Skip if not to be dumped */
10519         if (!opcinfo->dobj.dump || dataOnly)
10520                 return;
10521
10522         /*
10523          * XXX currently we do not implement dumping of operator classes from
10524          * pre-7.3 databases.  This could be done but it seems not worth the
10525          * trouble.
10526          */
10527         if (fout->remoteVersion < 70300)
10528                 return;
10529
10530         query = createPQExpBuffer();
10531         q = createPQExpBuffer();
10532         delq = createPQExpBuffer();
10533         labelq = createPQExpBuffer();
10534
10535         /* Make sure we are in proper schema so regoperator works correctly */
10536         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10537
10538         /* Get additional fields from the pg_opclass row */
10539         if (fout->remoteVersion >= 80300)
10540         {
10541                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10542                                                   "opckeytype::pg_catalog.regtype, "
10543                                                   "opcdefault, opcfamily, "
10544                                                   "opfname AS opcfamilyname, "
10545                                                   "nspname AS opcfamilynsp, "
10546                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10547                                                   "FROM pg_catalog.pg_opclass c "
10548                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10549                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10550                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10551                                                   opcinfo->dobj.catId.oid);
10552         }
10553         else
10554         {
10555                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10556                                                   "opckeytype::pg_catalog.regtype, "
10557                                                   "opcdefault, NULL AS opcfamily, "
10558                                                   "NULL AS opcfamilyname, "
10559                                                   "NULL AS opcfamilynsp, "
10560                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10561                                                   "FROM pg_catalog.pg_opclass "
10562                                                   "WHERE oid = '%u'::pg_catalog.oid",
10563                                                   opcinfo->dobj.catId.oid);
10564         }
10565
10566         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10567
10568         i_opcintype = PQfnumber(res, "opcintype");
10569         i_opckeytype = PQfnumber(res, "opckeytype");
10570         i_opcdefault = PQfnumber(res, "opcdefault");
10571         i_opcfamily = PQfnumber(res, "opcfamily");
10572         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10573         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10574         i_amname = PQfnumber(res, "amname");
10575
10576         opcintype = PQgetvalue(res, 0, i_opcintype);
10577         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10578         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10579         /* opcfamily will still be needed after we PQclear res */
10580         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10581         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10582         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10583         /* amname will still be needed after we PQclear res */
10584         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10585
10586         /*
10587          * DROP must be fully qualified in case same name appears in pg_catalog
10588          */
10589         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10590                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10591         appendPQExpBuffer(delq, ".%s",
10592                                           fmtId(opcinfo->dobj.name));
10593         appendPQExpBuffer(delq, " USING %s;\n",
10594                                           fmtId(amname));
10595
10596         /* Build the fixed portion of the CREATE command */
10597         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10598                                           fmtId(opcinfo->dobj.name));
10599         if (strcmp(opcdefault, "t") == 0)
10600                 appendPQExpBuffer(q, "DEFAULT ");
10601         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10602                                           opcintype,
10603                                           fmtId(amname));
10604         if (strlen(opcfamilyname) > 0 &&
10605                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10606                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10607         {
10608                 appendPQExpBuffer(q, " FAMILY ");
10609                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10610                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10611                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10612         }
10613         appendPQExpBuffer(q, " AS\n    ");
10614
10615         needComma = false;
10616
10617         if (strcmp(opckeytype, "-") != 0)
10618         {
10619                 appendPQExpBuffer(q, "STORAGE %s",
10620                                                   opckeytype);
10621                 needComma = true;
10622         }
10623
10624         PQclear(res);
10625
10626         /*
10627          * Now fetch and print the OPERATOR entries (pg_amop rows).
10628          *
10629          * Print only those opfamily members that are tied to the opclass by
10630          * pg_depend entries.
10631          *
10632          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10633          * older server's opclass in which it is used.  This is to avoid
10634          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10635          * older server and then reload into that old version.  This can go away
10636          * once 8.3 is so old as to not be of interest to anyone.
10637          */
10638         resetPQExpBuffer(query);
10639
10640         if (fout->remoteVersion >= 90100)
10641         {
10642                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10643                                                   "amopopr::pg_catalog.regoperator, "
10644                                                   "opfname AS sortfamily, "
10645                                                   "nspname AS sortfamilynsp "
10646                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10647                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10648                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10649                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10650                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10651                                                   "AND refobjid = '%u'::pg_catalog.oid "
10652                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10653                                                   "ORDER BY amopstrategy",
10654                                                   opcinfo->dobj.catId.oid,
10655                                                   opcfamily);
10656         }
10657         else if (fout->remoteVersion >= 80400)
10658         {
10659                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10660                                                   "amopopr::pg_catalog.regoperator, "
10661                                                   "NULL AS sortfamily, "
10662                                                   "NULL AS sortfamilynsp "
10663                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10664                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10665                                                   "AND refobjid = '%u'::pg_catalog.oid "
10666                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10667                                                   "AND objid = ao.oid "
10668                                                   "ORDER BY amopstrategy",
10669                                                   opcinfo->dobj.catId.oid);
10670         }
10671         else if (fout->remoteVersion >= 80300)
10672         {
10673                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10674                                                   "amopopr::pg_catalog.regoperator, "
10675                                                   "NULL AS sortfamily, "
10676                                                   "NULL AS sortfamilynsp "
10677                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10678                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10679                                                   "AND refobjid = '%u'::pg_catalog.oid "
10680                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10681                                                   "AND objid = ao.oid "
10682                                                   "ORDER BY amopstrategy",
10683                                                   opcinfo->dobj.catId.oid);
10684         }
10685         else
10686         {
10687                 /*
10688                  * Here, we print all entries since there are no opfamilies and hence
10689                  * no loose operators to worry about.
10690                  */
10691                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10692                                                   "amopopr::pg_catalog.regoperator, "
10693                                                   "NULL AS sortfamily, "
10694                                                   "NULL AS sortfamilynsp "
10695                                                   "FROM pg_catalog.pg_amop "
10696                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10697                                                   "ORDER BY amopstrategy",
10698                                                   opcinfo->dobj.catId.oid);
10699         }
10700
10701         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10702
10703         ntups = PQntuples(res);
10704
10705         i_amopstrategy = PQfnumber(res, "amopstrategy");
10706         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10707         i_amopopr = PQfnumber(res, "amopopr");
10708         i_sortfamily = PQfnumber(res, "sortfamily");
10709         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10710
10711         for (i = 0; i < ntups; i++)
10712         {
10713                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10714                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10715                 amopopr = PQgetvalue(res, i, i_amopopr);
10716                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10717                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10718
10719                 if (needComma)
10720                         appendPQExpBuffer(q, " ,\n    ");
10721
10722                 appendPQExpBuffer(q, "OPERATOR %s %s",
10723                                                   amopstrategy, amopopr);
10724
10725                 if (strlen(sortfamily) > 0)
10726                 {
10727                         appendPQExpBuffer(q, " FOR ORDER BY ");
10728                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10729                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10730                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10731                 }
10732
10733                 if (strcmp(amopreqcheck, "t") == 0)
10734                         appendPQExpBuffer(q, " RECHECK");
10735
10736                 needComma = true;
10737         }
10738
10739         PQclear(res);
10740
10741         /*
10742          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10743          *
10744          * Print only those opfamily members that are tied to the opclass by
10745          * pg_depend entries.
10746          *
10747          * We print the amproclefttype/amprocrighttype even though in most cases
10748          * the backend could deduce the right values, because of the corner case
10749          * of a btree sort support function for a cross-type comparison.  That's
10750          * only allowed in 9.2 and later, but for simplicity print them in all
10751          * versions that have the columns.
10752          */
10753         resetPQExpBuffer(query);
10754
10755         if (fout->remoteVersion >= 80300)
10756         {
10757                 appendPQExpBuffer(query, "SELECT amprocnum, "
10758                                                   "amproc::pg_catalog.regprocedure, "
10759                                                   "amproclefttype::pg_catalog.regtype, "
10760                                                   "amprocrighttype::pg_catalog.regtype "
10761                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10762                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10763                                                   "AND refobjid = '%u'::pg_catalog.oid "
10764                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10765                                                   "AND objid = ap.oid "
10766                                                   "ORDER BY amprocnum",
10767                                                   opcinfo->dobj.catId.oid);
10768         }
10769         else
10770         {
10771                 appendPQExpBuffer(query, "SELECT amprocnum, "
10772                                                   "amproc::pg_catalog.regprocedure, "
10773                                                   "'' AS amproclefttype, "
10774                                                   "'' AS amprocrighttype "
10775                                                   "FROM pg_catalog.pg_amproc "
10776                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10777                                                   "ORDER BY amprocnum",
10778                                                   opcinfo->dobj.catId.oid);
10779         }
10780
10781         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10782
10783         ntups = PQntuples(res);
10784
10785         i_amprocnum = PQfnumber(res, "amprocnum");
10786         i_amproc = PQfnumber(res, "amproc");
10787         i_amproclefttype = PQfnumber(res, "amproclefttype");
10788         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10789
10790         for (i = 0; i < ntups; i++)
10791         {
10792                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10793                 amproc = PQgetvalue(res, i, i_amproc);
10794                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10795                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10796
10797                 if (needComma)
10798                         appendPQExpBuffer(q, " ,\n    ");
10799
10800                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10801
10802                 if (*amproclefttype && *amprocrighttype)
10803                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10804
10805                 appendPQExpBuffer(q, " %s", amproc);
10806
10807                 needComma = true;
10808         }
10809
10810         PQclear(res);
10811
10812         appendPQExpBuffer(q, ";\n");
10813
10814         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10815                                           fmtId(opcinfo->dobj.name));
10816         appendPQExpBuffer(labelq, " USING %s",
10817                                           fmtId(amname));
10818
10819         if (binary_upgrade)
10820                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10821
10822         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10823                                  opcinfo->dobj.name,
10824                                  opcinfo->dobj.namespace->dobj.name,
10825                                  NULL,
10826                                  opcinfo->rolname,
10827                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10828                                  q->data, delq->data, NULL,
10829                                  NULL, 0,
10830                                  NULL, NULL);
10831
10832         /* Dump Operator Class Comments */
10833         dumpComment(fout, labelq->data,
10834                                 NULL, opcinfo->rolname,
10835                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10836
10837         free(amname);
10838         destroyPQExpBuffer(query);
10839         destroyPQExpBuffer(q);
10840         destroyPQExpBuffer(delq);
10841         destroyPQExpBuffer(labelq);
10842 }
10843
10844 /*
10845  * dumpOpfamily
10846  *        write out a single operator family definition
10847  *
10848  * Note: this also dumps any "loose" operator members that aren't bound to a
10849  * specific opclass within the opfamily.
10850  */
10851 static void
10852 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10853 {
10854         PQExpBuffer query;
10855         PQExpBuffer q;
10856         PQExpBuffer delq;
10857         PQExpBuffer labelq;
10858         PGresult   *res;
10859         PGresult   *res_ops;
10860         PGresult   *res_procs;
10861         int                     ntups;
10862         int                     i_amname;
10863         int                     i_amopstrategy;
10864         int                     i_amopreqcheck;
10865         int                     i_amopopr;
10866         int                     i_sortfamily;
10867         int                     i_sortfamilynsp;
10868         int                     i_amprocnum;
10869         int                     i_amproc;
10870         int                     i_amproclefttype;
10871         int                     i_amprocrighttype;
10872         char       *amname;
10873         char       *amopstrategy;
10874         char       *amopreqcheck;
10875         char       *amopopr;
10876         char       *sortfamily;
10877         char       *sortfamilynsp;
10878         char       *amprocnum;
10879         char       *amproc;
10880         char       *amproclefttype;
10881         char       *amprocrighttype;
10882         bool            needComma;
10883         int                     i;
10884
10885         /* Skip if not to be dumped */
10886         if (!opfinfo->dobj.dump || dataOnly)
10887                 return;
10888
10889         /*
10890          * We want to dump the opfamily only if (1) it contains "loose" operators
10891          * or functions, or (2) it contains an opclass with a different name or
10892          * owner.  Otherwise it's sufficient to let it be created during creation
10893          * of the contained opclass, and not dumping it improves portability of
10894          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10895          * that first.
10896          */
10897
10898         query = createPQExpBuffer();
10899         q = createPQExpBuffer();
10900         delq = createPQExpBuffer();
10901         labelq = createPQExpBuffer();
10902
10903         /* Make sure we are in proper schema so regoperator works correctly */
10904         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
10905
10906         /*
10907          * Fetch only those opfamily members that are tied directly to the
10908          * opfamily by pg_depend entries.
10909          *
10910          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10911          * older server's opclass in which it is used.  This is to avoid
10912          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10913          * older server and then reload into that old version.  This can go away
10914          * once 8.3 is so old as to not be of interest to anyone.
10915          */
10916         if (fout->remoteVersion >= 90100)
10917         {
10918                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10919                                                   "amopopr::pg_catalog.regoperator, "
10920                                                   "opfname AS sortfamily, "
10921                                                   "nspname AS sortfamilynsp "
10922                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10923                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10924                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10925                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10926                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10927                                                   "AND refobjid = '%u'::pg_catalog.oid "
10928                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10929                                                   "ORDER BY amopstrategy",
10930                                                   opfinfo->dobj.catId.oid,
10931                                                   opfinfo->dobj.catId.oid);
10932         }
10933         else if (fout->remoteVersion >= 80400)
10934         {
10935                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10936                                                   "amopopr::pg_catalog.regoperator, "
10937                                                   "NULL AS sortfamily, "
10938                                                   "NULL AS sortfamilynsp "
10939                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10940                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10941                                                   "AND refobjid = '%u'::pg_catalog.oid "
10942                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10943                                                   "AND objid = ao.oid "
10944                                                   "ORDER BY amopstrategy",
10945                                                   opfinfo->dobj.catId.oid);
10946         }
10947         else
10948         {
10949                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10950                                                   "amopopr::pg_catalog.regoperator, "
10951                                                   "NULL AS sortfamily, "
10952                                                   "NULL AS sortfamilynsp "
10953                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10954                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10955                                                   "AND refobjid = '%u'::pg_catalog.oid "
10956                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10957                                                   "AND objid = ao.oid "
10958                                                   "ORDER BY amopstrategy",
10959                                                   opfinfo->dobj.catId.oid);
10960         }
10961
10962         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10963
10964         resetPQExpBuffer(query);
10965
10966         appendPQExpBuffer(query, "SELECT amprocnum, "
10967                                           "amproc::pg_catalog.regprocedure, "
10968                                           "amproclefttype::pg_catalog.regtype, "
10969                                           "amprocrighttype::pg_catalog.regtype "
10970                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10971                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10972                                           "AND refobjid = '%u'::pg_catalog.oid "
10973                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10974                                           "AND objid = ap.oid "
10975                                           "ORDER BY amprocnum",
10976                                           opfinfo->dobj.catId.oid);
10977
10978         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10979
10980         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10981         {
10982                 /* No loose members, so check contained opclasses */
10983                 resetPQExpBuffer(query);
10984
10985                 appendPQExpBuffer(query, "SELECT 1 "
10986                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10987                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
10988                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10989                                                   "AND refobjid = f.oid "
10990                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10991                                                   "AND objid = c.oid "
10992                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10993                                                   "LIMIT 1",
10994                                                   opfinfo->dobj.catId.oid);
10995
10996                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10997
10998                 if (PQntuples(res) == 0)
10999                 {
11000                         /* no need to dump it, so bail out */
11001                         PQclear(res);
11002                         PQclear(res_ops);
11003                         PQclear(res_procs);
11004                         destroyPQExpBuffer(query);
11005                         destroyPQExpBuffer(q);
11006                         destroyPQExpBuffer(delq);
11007                         destroyPQExpBuffer(labelq);
11008                         return;
11009                 }
11010
11011                 PQclear(res);
11012         }
11013
11014         /* Get additional fields from the pg_opfamily row */
11015         resetPQExpBuffer(query);
11016
11017         appendPQExpBuffer(query, "SELECT "
11018          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11019                                           "FROM pg_catalog.pg_opfamily "
11020                                           "WHERE oid = '%u'::pg_catalog.oid",
11021                                           opfinfo->dobj.catId.oid);
11022
11023         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11024
11025         i_amname = PQfnumber(res, "amname");
11026
11027         /* amname will still be needed after we PQclear res */
11028         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11029
11030         /*
11031          * DROP must be fully qualified in case same name appears in pg_catalog
11032          */
11033         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11034                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11035         appendPQExpBuffer(delq, ".%s",
11036                                           fmtId(opfinfo->dobj.name));
11037         appendPQExpBuffer(delq, " USING %s;\n",
11038                                           fmtId(amname));
11039
11040         /* Build the fixed portion of the CREATE command */
11041         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11042                                           fmtId(opfinfo->dobj.name));
11043         appendPQExpBuffer(q, " USING %s;\n",
11044                                           fmtId(amname));
11045
11046         PQclear(res);
11047
11048         /* Do we need an ALTER to add loose members? */
11049         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11050         {
11051                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11052                                                   fmtId(opfinfo->dobj.name));
11053                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11054                                                   fmtId(amname));
11055
11056                 needComma = false;
11057
11058                 /*
11059                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11060                  */
11061                 ntups = PQntuples(res_ops);
11062
11063                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11064                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11065                 i_amopopr = PQfnumber(res_ops, "amopopr");
11066                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11067                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11068
11069                 for (i = 0; i < ntups; i++)
11070                 {
11071                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11072                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11073                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11074                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11075                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11076
11077                         if (needComma)
11078                                 appendPQExpBuffer(q, " ,\n    ");
11079
11080                         appendPQExpBuffer(q, "OPERATOR %s %s",
11081                                                           amopstrategy, amopopr);
11082
11083                         if (strlen(sortfamily) > 0)
11084                         {
11085                                 appendPQExpBuffer(q, " FOR ORDER BY ");
11086                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11087                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11088                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
11089                         }
11090
11091                         if (strcmp(amopreqcheck, "t") == 0)
11092                                 appendPQExpBuffer(q, " RECHECK");
11093
11094                         needComma = true;
11095                 }
11096
11097                 /*
11098                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11099                  */
11100                 ntups = PQntuples(res_procs);
11101
11102                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11103                 i_amproc = PQfnumber(res_procs, "amproc");
11104                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11105                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11106
11107                 for (i = 0; i < ntups; i++)
11108                 {
11109                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11110                         amproc = PQgetvalue(res_procs, i, i_amproc);
11111                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11112                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11113
11114                         if (needComma)
11115                                 appendPQExpBuffer(q, " ,\n    ");
11116
11117                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11118                                                           amprocnum, amproclefttype, amprocrighttype,
11119                                                           amproc);
11120
11121                         needComma = true;
11122                 }
11123
11124                 appendPQExpBuffer(q, ";\n");
11125         }
11126
11127         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11128                                           fmtId(opfinfo->dobj.name));
11129         appendPQExpBuffer(labelq, " USING %s",
11130                                           fmtId(amname));
11131
11132         if (binary_upgrade)
11133                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11134
11135         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11136                                  opfinfo->dobj.name,
11137                                  opfinfo->dobj.namespace->dobj.name,
11138                                  NULL,
11139                                  opfinfo->rolname,
11140                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11141                                  q->data, delq->data, NULL,
11142                                  NULL, 0,
11143                                  NULL, NULL);
11144
11145         /* Dump Operator Family Comments */
11146         dumpComment(fout, labelq->data,
11147                                 NULL, opfinfo->rolname,
11148                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11149
11150         free(amname);
11151         PQclear(res_ops);
11152         PQclear(res_procs);
11153         destroyPQExpBuffer(query);
11154         destroyPQExpBuffer(q);
11155         destroyPQExpBuffer(delq);
11156         destroyPQExpBuffer(labelq);
11157 }
11158
11159 /*
11160  * dumpCollation
11161  *        write out a single collation definition
11162  */
11163 static void
11164 dumpCollation(Archive *fout, CollInfo *collinfo)
11165 {
11166         PQExpBuffer query;
11167         PQExpBuffer q;
11168         PQExpBuffer delq;
11169         PQExpBuffer labelq;
11170         PGresult   *res;
11171         int                     i_collcollate;
11172         int                     i_collctype;
11173         const char *collcollate;
11174         const char *collctype;
11175
11176         /* Skip if not to be dumped */
11177         if (!collinfo->dobj.dump || dataOnly)
11178                 return;
11179
11180         query = createPQExpBuffer();
11181         q = createPQExpBuffer();
11182         delq = createPQExpBuffer();
11183         labelq = createPQExpBuffer();
11184
11185         /* Make sure we are in proper schema */
11186         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11187
11188         /* Get conversion-specific details */
11189         appendPQExpBuffer(query, "SELECT "
11190                                           "collcollate, "
11191                                           "collctype "
11192                                           "FROM pg_catalog.pg_collation c "
11193                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11194                                           collinfo->dobj.catId.oid);
11195
11196         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11197
11198         i_collcollate = PQfnumber(res, "collcollate");
11199         i_collctype = PQfnumber(res, "collctype");
11200
11201         collcollate = PQgetvalue(res, 0, i_collcollate);
11202         collctype = PQgetvalue(res, 0, i_collctype);
11203
11204         /*
11205          * DROP must be fully qualified in case same name appears in pg_catalog
11206          */
11207         appendPQExpBuffer(delq, "DROP COLLATION %s",
11208                                           fmtId(collinfo->dobj.namespace->dobj.name));
11209         appendPQExpBuffer(delq, ".%s;\n",
11210                                           fmtId(collinfo->dobj.name));
11211
11212         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11213                                           fmtId(collinfo->dobj.name));
11214         appendStringLiteralAH(q, collcollate, fout);
11215         appendPQExpBuffer(q, ", lc_ctype = ");
11216         appendStringLiteralAH(q, collctype, fout);
11217         appendPQExpBuffer(q, ");\n");
11218
11219         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11220
11221         if (binary_upgrade)
11222                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11223
11224         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11225                                  collinfo->dobj.name,
11226                                  collinfo->dobj.namespace->dobj.name,
11227                                  NULL,
11228                                  collinfo->rolname,
11229                                  false, "COLLATION", SECTION_PRE_DATA,
11230                                  q->data, delq->data, NULL,
11231                                  NULL, 0,
11232                                  NULL, NULL);
11233
11234         /* Dump Collation Comments */
11235         dumpComment(fout, labelq->data,
11236                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11237                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11238
11239         PQclear(res);
11240
11241         destroyPQExpBuffer(query);
11242         destroyPQExpBuffer(q);
11243         destroyPQExpBuffer(delq);
11244         destroyPQExpBuffer(labelq);
11245 }
11246
11247 /*
11248  * dumpConversion
11249  *        write out a single conversion definition
11250  */
11251 static void
11252 dumpConversion(Archive *fout, ConvInfo *convinfo)
11253 {
11254         PQExpBuffer query;
11255         PQExpBuffer q;
11256         PQExpBuffer delq;
11257         PQExpBuffer labelq;
11258         PGresult   *res;
11259         int                     i_conforencoding;
11260         int                     i_contoencoding;
11261         int                     i_conproc;
11262         int                     i_condefault;
11263         const char *conforencoding;
11264         const char *contoencoding;
11265         const char *conproc;
11266         bool            condefault;
11267
11268         /* Skip if not to be dumped */
11269         if (!convinfo->dobj.dump || dataOnly)
11270                 return;
11271
11272         query = createPQExpBuffer();
11273         q = createPQExpBuffer();
11274         delq = createPQExpBuffer();
11275         labelq = createPQExpBuffer();
11276
11277         /* Make sure we are in proper schema */
11278         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11279
11280         /* Get conversion-specific details */
11281         appendPQExpBuffer(query, "SELECT "
11282                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11283                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11284                                           "conproc, condefault "
11285                                           "FROM pg_catalog.pg_conversion c "
11286                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11287                                           convinfo->dobj.catId.oid);
11288
11289         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11290
11291         i_conforencoding = PQfnumber(res, "conforencoding");
11292         i_contoencoding = PQfnumber(res, "contoencoding");
11293         i_conproc = PQfnumber(res, "conproc");
11294         i_condefault = PQfnumber(res, "condefault");
11295
11296         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11297         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11298         conproc = PQgetvalue(res, 0, i_conproc);
11299         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11300
11301         /*
11302          * DROP must be fully qualified in case same name appears in pg_catalog
11303          */
11304         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11305                                           fmtId(convinfo->dobj.namespace->dobj.name));
11306         appendPQExpBuffer(delq, ".%s;\n",
11307                                           fmtId(convinfo->dobj.name));
11308
11309         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11310                                           (condefault) ? "DEFAULT " : "",
11311                                           fmtId(convinfo->dobj.name));
11312         appendStringLiteralAH(q, conforencoding, fout);
11313         appendPQExpBuffer(q, " TO ");
11314         appendStringLiteralAH(q, contoencoding, fout);
11315         /* regproc is automatically quoted in 7.3 and above */
11316         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11317
11318         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11319
11320         if (binary_upgrade)
11321                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11322
11323         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11324                                  convinfo->dobj.name,
11325                                  convinfo->dobj.namespace->dobj.name,
11326                                  NULL,
11327                                  convinfo->rolname,
11328                                  false, "CONVERSION", SECTION_PRE_DATA,
11329                                  q->data, delq->data, NULL,
11330                                  NULL, 0,
11331                                  NULL, NULL);
11332
11333         /* Dump Conversion Comments */
11334         dumpComment(fout, labelq->data,
11335                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11336                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11337
11338         PQclear(res);
11339
11340         destroyPQExpBuffer(query);
11341         destroyPQExpBuffer(q);
11342         destroyPQExpBuffer(delq);
11343         destroyPQExpBuffer(labelq);
11344 }
11345
11346 /*
11347  * format_aggregate_signature: generate aggregate name and argument list
11348  *
11349  * The argument type names are qualified if needed.  The aggregate name
11350  * is never qualified.
11351  */
11352 static char *
11353 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11354 {
11355         PQExpBufferData buf;
11356         int                     j;
11357
11358         initPQExpBuffer(&buf);
11359         if (honor_quotes)
11360                 appendPQExpBuffer(&buf, "%s",
11361                                                   fmtId(agginfo->aggfn.dobj.name));
11362         else
11363                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
11364
11365         if (agginfo->aggfn.nargs == 0)
11366                 appendPQExpBuffer(&buf, "(*)");
11367         else
11368         {
11369                 appendPQExpBuffer(&buf, "(");
11370                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11371                 {
11372                         char       *typname;
11373
11374                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11375                                                                                    zeroAsOpaque);
11376
11377                         appendPQExpBuffer(&buf, "%s%s",
11378                                                           (j > 0) ? ", " : "",
11379                                                           typname);
11380                         free(typname);
11381                 }
11382                 appendPQExpBuffer(&buf, ")");
11383         }
11384         return buf.data;
11385 }
11386
11387 /*
11388  * dumpAgg
11389  *        write out a single aggregate definition
11390  */
11391 static void
11392 dumpAgg(Archive *fout, AggInfo *agginfo)
11393 {
11394         PQExpBuffer query;
11395         PQExpBuffer q;
11396         PQExpBuffer delq;
11397         PQExpBuffer labelq;
11398         PQExpBuffer details;
11399         char       *aggsig;
11400         char       *aggsig_tag;
11401         PGresult   *res;
11402         int                     i_aggtransfn;
11403         int                     i_aggfinalfn;
11404         int                     i_aggsortop;
11405         int                     i_aggtranstype;
11406         int                     i_agginitval;
11407         int                     i_convertok;
11408         const char *aggtransfn;
11409         const char *aggfinalfn;
11410         const char *aggsortop;
11411         const char *aggtranstype;
11412         const char *agginitval;
11413         bool            convertok;
11414
11415         /* Skip if not to be dumped */
11416         if (!agginfo->aggfn.dobj.dump || dataOnly)
11417                 return;
11418
11419         query = createPQExpBuffer();
11420         q = createPQExpBuffer();
11421         delq = createPQExpBuffer();
11422         labelq = createPQExpBuffer();
11423         details = createPQExpBuffer();
11424
11425         /* Make sure we are in proper schema */
11426         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11427
11428         /* Get aggregate-specific details */
11429         if (fout->remoteVersion >= 80100)
11430         {
11431                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11432                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11433                                                   "aggsortop::pg_catalog.regoperator, "
11434                                                   "agginitval, "
11435                                                   "'t'::boolean AS convertok "
11436                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11437                                                   "WHERE a.aggfnoid = p.oid "
11438                                                   "AND p.oid = '%u'::pg_catalog.oid",
11439                                                   agginfo->aggfn.dobj.catId.oid);
11440         }
11441         else if (fout->remoteVersion >= 70300)
11442         {
11443                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11444                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11445                                                   "0 AS aggsortop, "
11446                                                   "agginitval, "
11447                                                   "'t'::boolean AS convertok "
11448                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11449                                                   "WHERE a.aggfnoid = p.oid "
11450                                                   "AND p.oid = '%u'::pg_catalog.oid",
11451                                                   agginfo->aggfn.dobj.catId.oid);
11452         }
11453         else if (fout->remoteVersion >= 70100)
11454         {
11455                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11456                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11457                                                   "0 AS aggsortop, "
11458                                                   "agginitval, "
11459                                                   "'t'::boolean AS convertok "
11460                                                   "FROM pg_aggregate "
11461                                                   "WHERE oid = '%u'::oid",
11462                                                   agginfo->aggfn.dobj.catId.oid);
11463         }
11464         else
11465         {
11466                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11467                                                   "aggfinalfn, "
11468                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11469                                                   "0 AS aggsortop, "
11470                                                   "agginitval1 AS agginitval, "
11471                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11472                                                   "FROM pg_aggregate "
11473                                                   "WHERE oid = '%u'::oid",
11474                                                   agginfo->aggfn.dobj.catId.oid);
11475         }
11476
11477         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11478
11479         i_aggtransfn = PQfnumber(res, "aggtransfn");
11480         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11481         i_aggsortop = PQfnumber(res, "aggsortop");
11482         i_aggtranstype = PQfnumber(res, "aggtranstype");
11483         i_agginitval = PQfnumber(res, "agginitval");
11484         i_convertok = PQfnumber(res, "convertok");
11485
11486         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11487         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11488         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11489         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11490         agginitval = PQgetvalue(res, 0, i_agginitval);
11491         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11492
11493         aggsig = format_aggregate_signature(agginfo, fout, true);
11494         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11495
11496         if (!convertok)
11497         {
11498                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11499                                   aggsig);
11500                 return;
11501         }
11502
11503         if (fout->remoteVersion >= 70300)
11504         {
11505                 /* If using 7.3's regproc or regtype, data is already quoted */
11506                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11507                                                   aggtransfn,
11508                                                   aggtranstype);
11509         }
11510         else if (fout->remoteVersion >= 70100)
11511         {
11512                 /* format_type quotes, regproc does not */
11513                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11514                                                   fmtId(aggtransfn),
11515                                                   aggtranstype);
11516         }
11517         else
11518         {
11519                 /* need quotes all around */
11520                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11521                                                   fmtId(aggtransfn));
11522                 appendPQExpBuffer(details, "    STYPE = %s",
11523                                                   fmtId(aggtranstype));
11524         }
11525
11526         if (!PQgetisnull(res, 0, i_agginitval))
11527         {
11528                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11529                 appendStringLiteralAH(details, agginitval, fout);
11530         }
11531
11532         if (strcmp(aggfinalfn, "-") != 0)
11533         {
11534                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11535                                                   aggfinalfn);
11536         }
11537
11538         aggsortop = convertOperatorReference(fout, aggsortop);
11539         if (aggsortop)
11540         {
11541                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11542                                                   aggsortop);
11543         }
11544
11545         /*
11546          * DROP must be fully qualified in case same name appears in pg_catalog
11547          */
11548         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11549                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11550                                           aggsig);
11551
11552         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11553                                           aggsig, details->data);
11554
11555         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11556
11557         if (binary_upgrade)
11558                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11559
11560         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11561                                  aggsig_tag,
11562                                  agginfo->aggfn.dobj.namespace->dobj.name,
11563                                  NULL,
11564                                  agginfo->aggfn.rolname,
11565                                  false, "AGGREGATE", SECTION_PRE_DATA,
11566                                  q->data, delq->data, NULL,
11567                                  NULL, 0,
11568                                  NULL, NULL);
11569
11570         /* Dump Aggregate Comments */
11571         dumpComment(fout, labelq->data,
11572                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11573                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11574         dumpSecLabel(fout, labelq->data,
11575                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11576                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11577
11578         /*
11579          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11580          * command look like a function's GRANT; in particular this affects the
11581          * syntax for zero-argument aggregates.
11582          */
11583         free(aggsig);
11584         free(aggsig_tag);
11585
11586         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11587         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11588
11589         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11590                         "FUNCTION",
11591                         aggsig, NULL, aggsig_tag,
11592                         agginfo->aggfn.dobj.namespace->dobj.name,
11593                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11594
11595         free(aggsig);
11596         free(aggsig_tag);
11597
11598         PQclear(res);
11599
11600         destroyPQExpBuffer(query);
11601         destroyPQExpBuffer(q);
11602         destroyPQExpBuffer(delq);
11603         destroyPQExpBuffer(labelq);
11604         destroyPQExpBuffer(details);
11605 }
11606
11607 /*
11608  * dumpTSParser
11609  *        write out a single text search parser
11610  */
11611 static void
11612 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11613 {
11614         PQExpBuffer q;
11615         PQExpBuffer delq;
11616         PQExpBuffer labelq;
11617
11618         /* Skip if not to be dumped */
11619         if (!prsinfo->dobj.dump || dataOnly)
11620                 return;
11621
11622         q = createPQExpBuffer();
11623         delq = createPQExpBuffer();
11624         labelq = createPQExpBuffer();
11625
11626         /* Make sure we are in proper schema */
11627         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11628
11629         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11630                                           fmtId(prsinfo->dobj.name));
11631
11632         appendPQExpBuffer(q, "    START = %s,\n",
11633                                           convertTSFunction(fout, prsinfo->prsstart));
11634         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11635                                           convertTSFunction(fout, prsinfo->prstoken));
11636         appendPQExpBuffer(q, "    END = %s,\n",
11637                                           convertTSFunction(fout, prsinfo->prsend));
11638         if (prsinfo->prsheadline != InvalidOid)
11639                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11640                                                   convertTSFunction(fout, prsinfo->prsheadline));
11641         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11642                                           convertTSFunction(fout, prsinfo->prslextype));
11643
11644         /*
11645          * DROP must be fully qualified in case same name appears in pg_catalog
11646          */
11647         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11648                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11649         appendPQExpBuffer(delq, ".%s;\n",
11650                                           fmtId(prsinfo->dobj.name));
11651
11652         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11653                                           fmtId(prsinfo->dobj.name));
11654
11655         if (binary_upgrade)
11656                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11657
11658         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11659                                  prsinfo->dobj.name,
11660                                  prsinfo->dobj.namespace->dobj.name,
11661                                  NULL,
11662                                  "",
11663                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11664                                  q->data, delq->data, NULL,
11665                                  NULL, 0,
11666                                  NULL, NULL);
11667
11668         /* Dump Parser Comments */
11669         dumpComment(fout, labelq->data,
11670                                 NULL, "",
11671                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11672
11673         destroyPQExpBuffer(q);
11674         destroyPQExpBuffer(delq);
11675         destroyPQExpBuffer(labelq);
11676 }
11677
11678 /*
11679  * dumpTSDictionary
11680  *        write out a single text search dictionary
11681  */
11682 static void
11683 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11684 {
11685         PQExpBuffer q;
11686         PQExpBuffer delq;
11687         PQExpBuffer labelq;
11688         PQExpBuffer query;
11689         PGresult   *res;
11690         char       *nspname;
11691         char       *tmplname;
11692
11693         /* Skip if not to be dumped */
11694         if (!dictinfo->dobj.dump || dataOnly)
11695                 return;
11696
11697         q = createPQExpBuffer();
11698         delq = createPQExpBuffer();
11699         labelq = createPQExpBuffer();
11700         query = createPQExpBuffer();
11701
11702         /* Fetch name and namespace of the dictionary's template */
11703         selectSourceSchema(fout, "pg_catalog");
11704         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11705                                           "FROM pg_ts_template p, pg_namespace n "
11706                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11707                                           dictinfo->dicttemplate);
11708         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11709         nspname = PQgetvalue(res, 0, 0);
11710         tmplname = PQgetvalue(res, 0, 1);
11711
11712         /* Make sure we are in proper schema */
11713         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11714
11715         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11716                                           fmtId(dictinfo->dobj.name));
11717
11718         appendPQExpBuffer(q, "    TEMPLATE = ");
11719         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11720                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11721         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11722
11723         PQclear(res);
11724
11725         /* the dictinitoption can be dumped straight into the command */
11726         if (dictinfo->dictinitoption)
11727                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11728
11729         appendPQExpBuffer(q, " );\n");
11730
11731         /*
11732          * DROP must be fully qualified in case same name appears in pg_catalog
11733          */
11734         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11735                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11736         appendPQExpBuffer(delq, ".%s;\n",
11737                                           fmtId(dictinfo->dobj.name));
11738
11739         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11740                                           fmtId(dictinfo->dobj.name));
11741
11742         if (binary_upgrade)
11743                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11744
11745         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11746                                  dictinfo->dobj.name,
11747                                  dictinfo->dobj.namespace->dobj.name,
11748                                  NULL,
11749                                  dictinfo->rolname,
11750                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11751                                  q->data, delq->data, NULL,
11752                                  NULL, 0,
11753                                  NULL, NULL);
11754
11755         /* Dump Dictionary Comments */
11756         dumpComment(fout, labelq->data,
11757                                 NULL, dictinfo->rolname,
11758                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11759
11760         destroyPQExpBuffer(q);
11761         destroyPQExpBuffer(delq);
11762         destroyPQExpBuffer(labelq);
11763         destroyPQExpBuffer(query);
11764 }
11765
11766 /*
11767  * dumpTSTemplate
11768  *        write out a single text search template
11769  */
11770 static void
11771 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11772 {
11773         PQExpBuffer q;
11774         PQExpBuffer delq;
11775         PQExpBuffer labelq;
11776
11777         /* Skip if not to be dumped */
11778         if (!tmplinfo->dobj.dump || dataOnly)
11779                 return;
11780
11781         q = createPQExpBuffer();
11782         delq = createPQExpBuffer();
11783         labelq = createPQExpBuffer();
11784
11785         /* Make sure we are in proper schema */
11786         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11787
11788         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11789                                           fmtId(tmplinfo->dobj.name));
11790
11791         if (tmplinfo->tmplinit != InvalidOid)
11792                 appendPQExpBuffer(q, "    INIT = %s,\n",
11793                                                   convertTSFunction(fout, tmplinfo->tmplinit));
11794         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11795                                           convertTSFunction(fout, tmplinfo->tmpllexize));
11796
11797         /*
11798          * DROP must be fully qualified in case same name appears in pg_catalog
11799          */
11800         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11801                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11802         appendPQExpBuffer(delq, ".%s;\n",
11803                                           fmtId(tmplinfo->dobj.name));
11804
11805         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11806                                           fmtId(tmplinfo->dobj.name));
11807
11808         if (binary_upgrade)
11809                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11810
11811         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11812                                  tmplinfo->dobj.name,
11813                                  tmplinfo->dobj.namespace->dobj.name,
11814                                  NULL,
11815                                  "",
11816                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11817                                  q->data, delq->data, NULL,
11818                                  NULL, 0,
11819                                  NULL, NULL);
11820
11821         /* Dump Template Comments */
11822         dumpComment(fout, labelq->data,
11823                                 NULL, "",
11824                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11825
11826         destroyPQExpBuffer(q);
11827         destroyPQExpBuffer(delq);
11828         destroyPQExpBuffer(labelq);
11829 }
11830
11831 /*
11832  * dumpTSConfig
11833  *        write out a single text search configuration
11834  */
11835 static void
11836 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11837 {
11838         PQExpBuffer q;
11839         PQExpBuffer delq;
11840         PQExpBuffer labelq;
11841         PQExpBuffer query;
11842         PGresult   *res;
11843         char       *nspname;
11844         char       *prsname;
11845         int                     ntups,
11846                                 i;
11847         int                     i_tokenname;
11848         int                     i_dictname;
11849
11850         /* Skip if not to be dumped */
11851         if (!cfginfo->dobj.dump || dataOnly)
11852                 return;
11853
11854         q = createPQExpBuffer();
11855         delq = createPQExpBuffer();
11856         labelq = createPQExpBuffer();
11857         query = createPQExpBuffer();
11858
11859         /* Fetch name and namespace of the config's parser */
11860         selectSourceSchema(fout, "pg_catalog");
11861         appendPQExpBuffer(query, "SELECT nspname, prsname "
11862                                           "FROM pg_ts_parser p, pg_namespace n "
11863                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11864                                           cfginfo->cfgparser);
11865         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11866         nspname = PQgetvalue(res, 0, 0);
11867         prsname = PQgetvalue(res, 0, 1);
11868
11869         /* Make sure we are in proper schema */
11870         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
11871
11872         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11873                                           fmtId(cfginfo->dobj.name));
11874
11875         appendPQExpBuffer(q, "    PARSER = ");
11876         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11877                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11878         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11879
11880         PQclear(res);
11881
11882         resetPQExpBuffer(query);
11883         appendPQExpBuffer(query,
11884                                           "SELECT \n"
11885                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11886                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11887                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11888                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11889                                           "WHERE m.mapcfg = '%u' \n"
11890                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11891                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11892
11893         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11894         ntups = PQntuples(res);
11895
11896         i_tokenname = PQfnumber(res, "tokenname");
11897         i_dictname = PQfnumber(res, "dictname");
11898
11899         for (i = 0; i < ntups; i++)
11900         {
11901                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11902                 char       *dictname = PQgetvalue(res, i, i_dictname);
11903
11904                 if (i == 0 ||
11905                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11906                 {
11907                         /* starting a new token type, so start a new command */
11908                         if (i > 0)
11909                                 appendPQExpBuffer(q, ";\n");
11910                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11911                                                           fmtId(cfginfo->dobj.name));
11912                         /* tokenname needs quoting, dictname does NOT */
11913                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11914                                                           fmtId(tokenname), dictname);
11915                 }
11916                 else
11917                         appendPQExpBuffer(q, ", %s", dictname);
11918         }
11919
11920         if (ntups > 0)
11921                 appendPQExpBuffer(q, ";\n");
11922
11923         PQclear(res);
11924
11925         /*
11926          * DROP must be fully qualified in case same name appears in pg_catalog
11927          */
11928         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11929                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11930         appendPQExpBuffer(delq, ".%s;\n",
11931                                           fmtId(cfginfo->dobj.name));
11932
11933         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11934                                           fmtId(cfginfo->dobj.name));
11935
11936         if (binary_upgrade)
11937                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11938
11939         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11940                                  cfginfo->dobj.name,
11941                                  cfginfo->dobj.namespace->dobj.name,
11942                                  NULL,
11943                                  cfginfo->rolname,
11944                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11945                                  q->data, delq->data, NULL,
11946                                  NULL, 0,
11947                                  NULL, NULL);
11948
11949         /* Dump Configuration Comments */
11950         dumpComment(fout, labelq->data,
11951                                 NULL, cfginfo->rolname,
11952                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11953
11954         destroyPQExpBuffer(q);
11955         destroyPQExpBuffer(delq);
11956         destroyPQExpBuffer(labelq);
11957         destroyPQExpBuffer(query);
11958 }
11959
11960 /*
11961  * dumpForeignDataWrapper
11962  *        write out a single foreign-data wrapper definition
11963  */
11964 static void
11965 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11966 {
11967         PQExpBuffer q;
11968         PQExpBuffer delq;
11969         PQExpBuffer labelq;
11970         char       *qfdwname;
11971
11972         /* Skip if not to be dumped */
11973         if (!fdwinfo->dobj.dump || dataOnly)
11974                 return;
11975
11976         /*
11977          * FDWs that belong to an extension are dumped based on their "dump"
11978          * field. Otherwise omit them if we are only dumping some specific object.
11979          */
11980         if (!fdwinfo->dobj.ext_member)
11981                 if (!include_everything)
11982                         return;
11983
11984         q = createPQExpBuffer();
11985         delq = createPQExpBuffer();
11986         labelq = createPQExpBuffer();
11987
11988         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11989
11990         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11991                                           qfdwname);
11992
11993         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11994                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11995
11996         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11997                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11998
11999         if (strlen(fdwinfo->fdwoptions) > 0)
12000                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12001
12002         appendPQExpBuffer(q, ";\n");
12003
12004         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12005                                           qfdwname);
12006
12007         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12008                                           qfdwname);
12009
12010         if (binary_upgrade)
12011                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12012
12013         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12014                                  fdwinfo->dobj.name,
12015                                  NULL,
12016                                  NULL,
12017                                  fdwinfo->rolname,
12018                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12019                                  q->data, delq->data, NULL,
12020                                  NULL, 0,
12021                                  NULL, NULL);
12022
12023         /* Handle the ACL */
12024         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12025                         "FOREIGN DATA WRAPPER",
12026                         qfdwname, NULL, fdwinfo->dobj.name,
12027                         NULL, fdwinfo->rolname,
12028                         fdwinfo->fdwacl);
12029
12030         /* Dump Foreign Data Wrapper Comments */
12031         dumpComment(fout, labelq->data,
12032                                 NULL, fdwinfo->rolname,
12033                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12034
12035         free(qfdwname);
12036
12037         destroyPQExpBuffer(q);
12038         destroyPQExpBuffer(delq);
12039         destroyPQExpBuffer(labelq);
12040 }
12041
12042 /*
12043  * dumpForeignServer
12044  *        write out a foreign server definition
12045  */
12046 static void
12047 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12048 {
12049         PQExpBuffer q;
12050         PQExpBuffer delq;
12051         PQExpBuffer labelq;
12052         PQExpBuffer query;
12053         PGresult   *res;
12054         char       *qsrvname;
12055         char       *fdwname;
12056
12057         /* Skip if not to be dumped */
12058         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12059                 return;
12060
12061         q = createPQExpBuffer();
12062         delq = createPQExpBuffer();
12063         labelq = createPQExpBuffer();
12064         query = createPQExpBuffer();
12065
12066         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12067
12068         /* look up the foreign-data wrapper */
12069         selectSourceSchema(fout, "pg_catalog");
12070         appendPQExpBuffer(query, "SELECT fdwname "
12071                                           "FROM pg_foreign_data_wrapper w "
12072                                           "WHERE w.oid = '%u'",
12073                                           srvinfo->srvfdw);
12074         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12075         fdwname = PQgetvalue(res, 0, 0);
12076
12077         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12078         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12079         {
12080                 appendPQExpBuffer(q, " TYPE ");
12081                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12082         }
12083         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12084         {
12085                 appendPQExpBuffer(q, " VERSION ");
12086                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12087         }
12088
12089         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
12090         appendPQExpBuffer(q, "%s", fmtId(fdwname));
12091
12092         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12093                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12094
12095         appendPQExpBuffer(q, ";\n");
12096
12097         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12098                                           qsrvname);
12099
12100         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12101
12102         if (binary_upgrade)
12103                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12104
12105         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12106                                  srvinfo->dobj.name,
12107                                  NULL,
12108                                  NULL,
12109                                  srvinfo->rolname,
12110                                  false, "SERVER", SECTION_PRE_DATA,
12111                                  q->data, delq->data, NULL,
12112                                  NULL, 0,
12113                                  NULL, NULL);
12114
12115         /* Handle the ACL */
12116         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12117                         "FOREIGN SERVER",
12118                         qsrvname, NULL, srvinfo->dobj.name,
12119                         NULL, srvinfo->rolname,
12120                         srvinfo->srvacl);
12121
12122         /* Dump user mappings */
12123         dumpUserMappings(fout,
12124                                          srvinfo->dobj.name, NULL,
12125                                          srvinfo->rolname,
12126                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12127
12128         /* Dump Foreign Server Comments */
12129         dumpComment(fout, labelq->data,
12130                                 NULL, srvinfo->rolname,
12131                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12132
12133         free(qsrvname);
12134
12135         destroyPQExpBuffer(q);
12136         destroyPQExpBuffer(delq);
12137         destroyPQExpBuffer(labelq);
12138 }
12139
12140 /*
12141  * dumpUserMappings
12142  *
12143  * This routine is used to dump any user mappings associated with the
12144  * server handed to this routine. Should be called after ArchiveEntry()
12145  * for the server.
12146  */
12147 static void
12148 dumpUserMappings(Archive *fout,
12149                                  const char *servername, const char *namespace,
12150                                  const char *owner,
12151                                  CatalogId catalogId, DumpId dumpId)
12152 {
12153         PQExpBuffer q;
12154         PQExpBuffer delq;
12155         PQExpBuffer query;
12156         PQExpBuffer tag;
12157         PGresult   *res;
12158         int                     ntups;
12159         int                     i_usename;
12160         int                     i_umoptions;
12161         int                     i;
12162
12163         q = createPQExpBuffer();
12164         tag = createPQExpBuffer();
12165         delq = createPQExpBuffer();
12166         query = createPQExpBuffer();
12167
12168         /*
12169          * We read from the publicly accessible view pg_user_mappings, so as not
12170          * to fail if run by a non-superuser.  Note that the view will show
12171          * umoptions as null if the user hasn't got privileges for the associated
12172          * server; this means that pg_dump will dump such a mapping, but with no
12173          * OPTIONS clause.      A possible alternative is to skip such mappings
12174          * altogether, but it's not clear that that's an improvement.
12175          */
12176         selectSourceSchema(fout, "pg_catalog");
12177
12178         appendPQExpBuffer(query,
12179                                           "SELECT usename, "
12180                                           "array_to_string(ARRAY("
12181                                           "SELECT quote_ident(option_name) || ' ' || "
12182                                           "quote_literal(option_value) "
12183                                           "FROM pg_options_to_table(umoptions) "
12184                                           "ORDER BY option_name"
12185                                           "), E',\n    ') AS umoptions "
12186                                           "FROM pg_user_mappings "
12187                                           "WHERE srvid = '%u' "
12188                                           "ORDER BY usename",
12189                                           catalogId.oid);
12190
12191         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12192
12193         ntups = PQntuples(res);
12194         i_usename = PQfnumber(res, "usename");
12195         i_umoptions = PQfnumber(res, "umoptions");
12196
12197         for (i = 0; i < ntups; i++)
12198         {
12199                 char       *usename;
12200                 char       *umoptions;
12201
12202                 usename = PQgetvalue(res, i, i_usename);
12203                 umoptions = PQgetvalue(res, i, i_umoptions);
12204
12205                 resetPQExpBuffer(q);
12206                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12207                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12208
12209                 if (umoptions && strlen(umoptions) > 0)
12210                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12211
12212                 appendPQExpBuffer(q, ";\n");
12213
12214                 resetPQExpBuffer(delq);
12215                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12216                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12217
12218                 resetPQExpBuffer(tag);
12219                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12220                                                   usename, servername);
12221
12222                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12223                                          tag->data,
12224                                          namespace,
12225                                          NULL,
12226                                          owner, false,
12227                                          "USER MAPPING", SECTION_PRE_DATA,
12228                                          q->data, delq->data, NULL,
12229                                          &dumpId, 1,
12230                                          NULL, NULL);
12231         }
12232
12233         PQclear(res);
12234
12235         destroyPQExpBuffer(query);
12236         destroyPQExpBuffer(delq);
12237         destroyPQExpBuffer(q);
12238 }
12239
12240 /*
12241  * Write out default privileges information
12242  */
12243 static void
12244 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12245 {
12246         PQExpBuffer q;
12247         PQExpBuffer tag;
12248         const char *type;
12249
12250         /* Skip if not to be dumped */
12251         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12252                 return;
12253
12254         q = createPQExpBuffer();
12255         tag = createPQExpBuffer();
12256
12257         switch (daclinfo->defaclobjtype)
12258         {
12259                 case DEFACLOBJ_RELATION:
12260                         type = "TABLES";
12261                         break;
12262                 case DEFACLOBJ_SEQUENCE:
12263                         type = "SEQUENCES";
12264                         break;
12265                 case DEFACLOBJ_FUNCTION:
12266                         type = "FUNCTIONS";
12267                         break;
12268                 case DEFACLOBJ_TYPE:
12269                         type = "TYPES";
12270                         break;
12271                 default:
12272                         /* shouldn't get here */
12273                         exit_horribly(NULL,
12274                                           "unrecognized object type in default privileges: %d\n",
12275                                                   (int) daclinfo->defaclobjtype);
12276                         type = "";                      /* keep compiler quiet */
12277         }
12278
12279         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12280
12281         /* build the actual command(s) for this tuple */
12282         if (!buildDefaultACLCommands(type,
12283                                                                  daclinfo->dobj.namespace != NULL ?
12284                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12285                                                                  daclinfo->defaclacl,
12286                                                                  daclinfo->defaclrole,
12287                                                                  fout->remoteVersion,
12288                                                                  q))
12289                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12290                                           daclinfo->defaclacl);
12291
12292         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12293                                  tag->data,
12294            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12295                                  NULL,
12296                                  daclinfo->defaclrole,
12297                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12298                                  q->data, "", NULL,
12299                                  NULL, 0,
12300                                  NULL, NULL);
12301
12302         destroyPQExpBuffer(tag);
12303         destroyPQExpBuffer(q);
12304 }
12305
12306 /*----------
12307  * Write out grant/revoke information
12308  *
12309  * 'objCatId' is the catalog ID of the underlying object.
12310  * 'objDumpId' is the dump ID of the underlying object.
12311  * 'type' must be one of
12312  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12313  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12314  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12315  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12316  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12317  * 'nspname' is the namespace the object is in (NULL if none).
12318  * 'owner' is the owner, NULL if there is no owner (for languages).
12319  * 'acls' is the string read out of the fooacl system catalog field;
12320  *              it will be parsed here.
12321  *----------
12322  */
12323 static void
12324 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12325                 const char *type, const char *name, const char *subname,
12326                 const char *tag, const char *nspname, const char *owner,
12327                 const char *acls)
12328 {
12329         PQExpBuffer sql;
12330
12331         /* Do nothing if ACL dump is not enabled */
12332         if (aclsSkip)
12333                 return;
12334
12335         /* --data-only skips ACLs *except* BLOB ACLs */
12336         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12337                 return;
12338
12339         sql = createPQExpBuffer();
12340
12341         if (!buildACLCommands(name, subname, type, acls, owner,
12342                                                   "", fout->remoteVersion, sql))
12343                 exit_horribly(NULL,
12344                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12345                                           acls, name, type);
12346
12347         if (sql->len > 0)
12348                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12349                                          tag, nspname,
12350                                          NULL,
12351                                          owner ? owner : "",
12352                                          false, "ACL", SECTION_NONE,
12353                                          sql->data, "", NULL,
12354                                          &(objDumpId), 1,
12355                                          NULL, NULL);
12356
12357         destroyPQExpBuffer(sql);
12358 }
12359
12360 /*
12361  * dumpSecLabel
12362  *
12363  * This routine is used to dump any security labels associated with the
12364  * object handed to this routine. The routine takes a constant character
12365  * string for the target part of the security-label command, plus
12366  * the namespace and owner of the object (for labeling the ArchiveEntry),
12367  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12368  * plus the dump ID for the object (for setting a dependency).
12369  * If a matching pg_seclabel entry is found, it is dumped.
12370  *
12371  * Note: although this routine takes a dumpId for dependency purposes,
12372  * that purpose is just to mark the dependency in the emitted dump file
12373  * for possible future use by pg_restore.  We do NOT use it for determining
12374  * ordering of the label in the dump file, because this routine is called
12375  * after dependency sorting occurs.  This routine should be called just after
12376  * calling ArchiveEntry() for the specified object.
12377  */
12378 static void
12379 dumpSecLabel(Archive *fout, const char *target,
12380                          const char *namespace, const char *owner,
12381                          CatalogId catalogId, int subid, DumpId dumpId)
12382 {
12383         SecLabelItem *labels;
12384         int                     nlabels;
12385         int                     i;
12386         PQExpBuffer query;
12387
12388         /* do nothing, if --no-security-labels is supplied */
12389         if (no_security_labels)
12390                 return;
12391
12392         /* Comments are schema not data ... except blob comments are data */
12393         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12394         {
12395                 if (dataOnly)
12396                         return;
12397         }
12398         else
12399         {
12400                 if (schemaOnly)
12401                         return;
12402         }
12403
12404         /* Search for security labels associated with catalogId, using table */
12405         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12406
12407         query = createPQExpBuffer();
12408
12409         for (i = 0; i < nlabels; i++)
12410         {
12411                 /*
12412                  * Ignore label entries for which the subid doesn't match.
12413                  */
12414                 if (labels[i].objsubid != subid)
12415                         continue;
12416
12417                 appendPQExpBuffer(query,
12418                                                   "SECURITY LABEL FOR %s ON %s IS ",
12419                                                   fmtId(labels[i].provider), target);
12420                 appendStringLiteralAH(query, labels[i].label, fout);
12421                 appendPQExpBuffer(query, ";\n");
12422         }
12423
12424         if (query->len > 0)
12425         {
12426                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12427                                          target, namespace, NULL, owner,
12428                                          false, "SECURITY LABEL", SECTION_NONE,
12429                                          query->data, "", NULL,
12430                                          &(dumpId), 1,
12431                                          NULL, NULL);
12432         }
12433         destroyPQExpBuffer(query);
12434 }
12435
12436 /*
12437  * dumpTableSecLabel
12438  *
12439  * As above, but dump security label for both the specified table (or view)
12440  * and its columns.
12441  */
12442 static void
12443 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12444 {
12445         SecLabelItem *labels;
12446         int                     nlabels;
12447         int                     i;
12448         PQExpBuffer query;
12449         PQExpBuffer target;
12450
12451         /* do nothing, if --no-security-labels is supplied */
12452         if (no_security_labels)
12453                 return;
12454
12455         /* SecLabel are SCHEMA not data */
12456         if (dataOnly)
12457                 return;
12458
12459         /* Search for comments associated with relation, using table */
12460         nlabels = findSecLabels(fout,
12461                                                         tbinfo->dobj.catId.tableoid,
12462                                                         tbinfo->dobj.catId.oid,
12463                                                         &labels);
12464
12465         /* If security labels exist, build SECURITY LABEL statements */
12466         if (nlabels <= 0)
12467                 return;
12468
12469         query = createPQExpBuffer();
12470         target = createPQExpBuffer();
12471
12472         for (i = 0; i < nlabels; i++)
12473         {
12474                 const char *colname;
12475                 const char *provider = labels[i].provider;
12476                 const char *label = labels[i].label;
12477                 int                     objsubid = labels[i].objsubid;
12478
12479                 resetPQExpBuffer(target);
12480                 if (objsubid == 0)
12481                 {
12482                         appendPQExpBuffer(target, "%s %s", reltypename,
12483                                                           fmtId(tbinfo->dobj.name));
12484                 }
12485                 else
12486                 {
12487                         colname = getAttrName(objsubid, tbinfo);
12488                         /* first fmtId result must be consumed before calling it again */
12489                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12490                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12491                 }
12492                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12493                                                   fmtId(provider), target->data);
12494                 appendStringLiteralAH(query, label, fout);
12495                 appendPQExpBuffer(query, ";\n");
12496         }
12497         if (query->len > 0)
12498         {
12499                 resetPQExpBuffer(target);
12500                 appendPQExpBuffer(target, "%s %s", reltypename,
12501                                                   fmtId(tbinfo->dobj.name));
12502                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12503                                          target->data,
12504                                          tbinfo->dobj.namespace->dobj.name,
12505                                          NULL, tbinfo->rolname,
12506                                          false, "SECURITY LABEL", SECTION_NONE,
12507                                          query->data, "", NULL,
12508                                          &(tbinfo->dobj.dumpId), 1,
12509                                          NULL, NULL);
12510         }
12511         destroyPQExpBuffer(query);
12512         destroyPQExpBuffer(target);
12513 }
12514
12515 /*
12516  * findSecLabels
12517  *
12518  * Find the security label(s), if any, associated with the given object.
12519  * All the objsubid values associated with the given classoid/objoid are
12520  * found with one search.
12521  */
12522 static int
12523 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12524 {
12525         /* static storage for table of security labels */
12526         static SecLabelItem *labels = NULL;
12527         static int      nlabels = -1;
12528
12529         SecLabelItem *middle = NULL;
12530         SecLabelItem *low;
12531         SecLabelItem *high;
12532         int                     nmatch;
12533
12534         /* Get security labels if we didn't already */
12535         if (nlabels < 0)
12536                 nlabels = collectSecLabels(fout, &labels);
12537
12538         if (nlabels <= 0)                       /* no labels, so no match is possible */
12539         {
12540                 *items = NULL;
12541                 return 0;
12542         }
12543
12544         /*
12545          * Do binary search to find some item matching the object.
12546          */
12547         low = &labels[0];
12548         high = &labels[nlabels - 1];
12549         while (low <= high)
12550         {
12551                 middle = low + (high - low) / 2;
12552
12553                 if (classoid < middle->classoid)
12554                         high = middle - 1;
12555                 else if (classoid > middle->classoid)
12556                         low = middle + 1;
12557                 else if (objoid < middle->objoid)
12558                         high = middle - 1;
12559                 else if (objoid > middle->objoid)
12560                         low = middle + 1;
12561                 else
12562                         break;                          /* found a match */
12563         }
12564
12565         if (low > high)                         /* no matches */
12566         {
12567                 *items = NULL;
12568                 return 0;
12569         }
12570
12571         /*
12572          * Now determine how many items match the object.  The search loop
12573          * invariant still holds: only items between low and high inclusive could
12574          * match.
12575          */
12576         nmatch = 1;
12577         while (middle > low)
12578         {
12579                 if (classoid != middle[-1].classoid ||
12580                         objoid != middle[-1].objoid)
12581                         break;
12582                 middle--;
12583                 nmatch++;
12584         }
12585
12586         *items = middle;
12587
12588         middle += nmatch;
12589         while (middle <= high)
12590         {
12591                 if (classoid != middle->classoid ||
12592                         objoid != middle->objoid)
12593                         break;
12594                 middle++;
12595                 nmatch++;
12596         }
12597
12598         return nmatch;
12599 }
12600
12601 /*
12602  * collectSecLabels
12603  *
12604  * Construct a table of all security labels available for database objects.
12605  * It's much faster to pull them all at once.
12606  *
12607  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12608  */
12609 static int
12610 collectSecLabels(Archive *fout, SecLabelItem **items)
12611 {
12612         PGresult   *res;
12613         PQExpBuffer query;
12614         int                     i_label;
12615         int                     i_provider;
12616         int                     i_classoid;
12617         int                     i_objoid;
12618         int                     i_objsubid;
12619         int                     ntups;
12620         int                     i;
12621         SecLabelItem *labels;
12622
12623         query = createPQExpBuffer();
12624
12625         appendPQExpBuffer(query,
12626                                           "SELECT label, provider, classoid, objoid, objsubid "
12627                                           "FROM pg_catalog.pg_seclabel "
12628                                           "ORDER BY classoid, objoid, objsubid");
12629
12630         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12631
12632         /* Construct lookup table containing OIDs in numeric form */
12633         i_label = PQfnumber(res, "label");
12634         i_provider = PQfnumber(res, "provider");
12635         i_classoid = PQfnumber(res, "classoid");
12636         i_objoid = PQfnumber(res, "objoid");
12637         i_objsubid = PQfnumber(res, "objsubid");
12638
12639         ntups = PQntuples(res);
12640
12641         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12642
12643         for (i = 0; i < ntups; i++)
12644         {
12645                 labels[i].label = PQgetvalue(res, i, i_label);
12646                 labels[i].provider = PQgetvalue(res, i, i_provider);
12647                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12648                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12649                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12650         }
12651
12652         /* Do NOT free the PGresult since we are keeping pointers into it */
12653         destroyPQExpBuffer(query);
12654
12655         *items = labels;
12656         return ntups;
12657 }
12658
12659 /*
12660  * dumpTable
12661  *        write out to fout the declarations (not data) of a user-defined table
12662  */
12663 static void
12664 dumpTable(Archive *fout, TableInfo *tbinfo)
12665 {
12666         if (tbinfo->dobj.dump && !dataOnly)
12667         {
12668                 char       *namecopy;
12669
12670                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12671                         dumpSequence(fout, tbinfo);
12672                 else
12673                         dumpTableSchema(fout, tbinfo);
12674
12675                 /* Handle the ACL here */
12676                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12677                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12678                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12679                                 "TABLE",
12680                                 namecopy, NULL, tbinfo->dobj.name,
12681                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12682                                 tbinfo->relacl);
12683
12684                 /*
12685                  * Handle column ACLs, if any.  Note: we pull these with a separate
12686                  * query rather than trying to fetch them during getTableAttrs, so
12687                  * that we won't miss ACLs on system columns.
12688                  */
12689                 if (fout->remoteVersion >= 80400)
12690                 {
12691                         PQExpBuffer query = createPQExpBuffer();
12692                         PGresult   *res;
12693                         int                     i;
12694
12695                         appendPQExpBuffer(query,
12696                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12697                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12698                                                           "ORDER BY attnum",
12699                                                           tbinfo->dobj.catId.oid);
12700                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12701
12702                         for (i = 0; i < PQntuples(res); i++)
12703                         {
12704                                 char       *attname = PQgetvalue(res, i, 0);
12705                                 char       *attacl = PQgetvalue(res, i, 1);
12706                                 char       *attnamecopy;
12707                                 char       *acltag;
12708
12709                                 attnamecopy = pg_strdup(fmtId(attname));
12710                                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12711                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12712                                 /* Column's GRANT type is always TABLE */
12713                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12714                                                 namecopy, attnamecopy, acltag,
12715                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12716                                                 attacl);
12717                                 free(attnamecopy);
12718                                 free(acltag);
12719                         }
12720                         PQclear(res);
12721                         destroyPQExpBuffer(query);
12722                 }
12723
12724                 free(namecopy);
12725         }
12726 }
12727
12728 /*
12729  * Create the AS clause for a view or materialized view. The semicolon is
12730  * stripped because a materialized view must add a WITH NO DATA clause.
12731  *
12732  * This returns a new buffer which must be freed by the caller.
12733  */
12734 static PQExpBuffer
12735 createViewAsClause(Archive *fout, TableInfo *tbinfo)
12736 {
12737         PQExpBuffer query = createPQExpBuffer();
12738         PQExpBuffer result = createPQExpBuffer();
12739         PGresult   *res;
12740         int                     len;
12741
12742         /* Fetch the view definition */
12743         if (fout->remoteVersion >= 70300)
12744         {
12745                 /* Beginning in 7.3, viewname is not unique; rely on OID */
12746                 appendPQExpBuffer(query,
12747                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12748                                                   tbinfo->dobj.catId.oid);
12749         }
12750         else
12751         {
12752                 appendPQExpBuffer(query, "SELECT definition AS viewdef "
12753                                                   "FROM pg_views WHERE viewname = ");
12754                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12755                 appendPQExpBuffer(query, ";");
12756         }
12757
12758         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12759
12760         if (PQntuples(res) != 1)
12761         {
12762                 if (PQntuples(res) < 1)
12763                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12764                                                   tbinfo->dobj.name);
12765                 else
12766                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12767                                                   tbinfo->dobj.name);
12768         }
12769
12770         len = PQgetlength(res, 0, 0);
12771
12772         if (len == 0)
12773                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12774                                           tbinfo->dobj.name);
12775
12776         /* Strip off the trailing semicolon so that other things may follow. */
12777         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
12778         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
12779
12780         PQclear(res);
12781         destroyPQExpBuffer(query);
12782
12783         return result;
12784 }
12785
12786 /*
12787  * dumpTableSchema
12788  *        write the declaration (not data) of one user-defined table or view
12789  */
12790 static void
12791 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12792 {
12793         PQExpBuffer q = createPQExpBuffer();
12794         PQExpBuffer delq = createPQExpBuffer();
12795         PQExpBuffer labelq = createPQExpBuffer();
12796         int                     numParents;
12797         TableInfo **parents;
12798         int                     actual_atts;    /* number of attrs in this CREATE statement */
12799         const char *reltypename;
12800         char       *storage;
12801         char       *srvname;
12802         char       *ftoptions;
12803         int                     j,
12804                                 k;
12805
12806         /* Make sure we are in proper schema */
12807         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12808
12809         if (binary_upgrade)
12810                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12811                                                                                                 tbinfo->dobj.catId.oid);
12812
12813         /* Is it a table or a view? */
12814         if (tbinfo->relkind == RELKIND_VIEW)
12815         {
12816                 PQExpBuffer result;
12817
12818                 reltypename = "VIEW";
12819
12820                 /*
12821                  * DROP must be fully qualified in case same name appears in
12822                  * pg_catalog
12823                  */
12824                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12825                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12826                 appendPQExpBuffer(delq, "%s;\n",
12827                                                   fmtId(tbinfo->dobj.name));
12828
12829                 if (binary_upgrade)
12830                         binary_upgrade_set_pg_class_oids(fout, q,
12831                                                                                          tbinfo->dobj.catId.oid, false);
12832
12833                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12834                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12835                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12836                 result = createViewAsClause(fout, tbinfo);
12837                 appendPQExpBuffer(q, " AS\n%s;\n", result->data);
12838                 destroyPQExpBuffer(result);
12839
12840                 appendPQExpBuffer(labelq, "VIEW %s",
12841                                                   fmtId(tbinfo->dobj.name));
12842         }
12843         else
12844         {
12845                 switch (tbinfo->relkind)
12846                 {
12847                         case (RELKIND_FOREIGN_TABLE):
12848                                 {
12849                                         PQExpBuffer query = createPQExpBuffer();
12850                                         PGresult   *res;
12851                                         int                     i_srvname;
12852                                         int                     i_ftoptions;
12853
12854                                         reltypename = "FOREIGN TABLE";
12855
12856                                         /* retrieve name of foreign server and generic options */
12857                                         appendPQExpBuffer(query,
12858                                                                           "SELECT fs.srvname, "
12859                                                                           "pg_catalog.array_to_string(ARRAY("
12860                                                          "SELECT pg_catalog.quote_ident(option_name) || "
12861                                                          "' ' || pg_catalog.quote_literal(option_value) "
12862                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
12863                                                                           "ORDER BY option_name"
12864                                                                           "), E',\n    ') AS ftoptions "
12865                                                                           "FROM pg_catalog.pg_foreign_table ft "
12866                                                                           "JOIN pg_catalog.pg_foreign_server fs "
12867                                                                           "ON (fs.oid = ft.ftserver) "
12868                                                                           "WHERE ft.ftrelid = '%u'",
12869                                                                           tbinfo->dobj.catId.oid);
12870                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12871                                         i_srvname = PQfnumber(res, "srvname");
12872                                         i_ftoptions = PQfnumber(res, "ftoptions");
12873                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12874                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12875                                         PQclear(res);
12876                                         destroyPQExpBuffer(query);
12877                                         break;
12878                                 }
12879                         case (RELKIND_MATVIEW):
12880                                 reltypename = "MATERIALIZED VIEW";
12881                                 srvname = NULL;
12882                                 ftoptions = NULL;
12883                                 break;
12884                         default:
12885                                 reltypename = "TABLE";
12886                                 srvname = NULL;
12887                                 ftoptions = NULL;
12888                 }
12889
12890                 numParents = tbinfo->numParents;
12891                 parents = tbinfo->parents;
12892
12893                 /*
12894                  * DROP must be fully qualified in case same name appears in
12895                  * pg_catalog
12896                  */
12897                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12898                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12899                 appendPQExpBuffer(delq, "%s;\n",
12900                                                   fmtId(tbinfo->dobj.name));
12901
12902                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12903                                                   fmtId(tbinfo->dobj.name));
12904
12905                 if (binary_upgrade)
12906                         binary_upgrade_set_pg_class_oids(fout, q,
12907                                                                                          tbinfo->dobj.catId.oid, false);
12908
12909                 appendPQExpBuffer(q, "CREATE %s%s %s",
12910                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12911                                                   "UNLOGGED " : "",
12912                                                   reltypename,
12913                                                   fmtId(tbinfo->dobj.name));
12914
12915                 /*
12916                  * Attach to type, if reloftype; except in case of a binary upgrade,
12917                  * we dump the table normally and attach it to the type afterward.
12918                  */
12919                 if (tbinfo->reloftype && !binary_upgrade)
12920                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12921
12922                 if (tbinfo->relkind != RELKIND_MATVIEW)
12923                 {
12924                         /* Dump the attributes */
12925                         actual_atts = 0;
12926                         for (j = 0; j < tbinfo->numatts; j++)
12927                         {
12928                                 /*
12929                                  * Normally, dump if it's locally defined in this table, and
12930                                  * not dropped.  But for binary upgrade, we'll dump all the
12931                                  * columns, and then fix up the dropped and nonlocal cases
12932                                  * below.
12933                                  */
12934                                 if (shouldPrintColumn(tbinfo, j))
12935                                 {
12936                                         /*
12937                                          * Default value --- suppress if to be printed separately.
12938                                          */
12939                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
12940                                                                                          !tbinfo->attrdefs[j]->separate);
12941
12942                                         /*
12943                                          * Not Null constraint --- suppress if inherited, except
12944                                          * in binary-upgrade case where that won't work.
12945                                          */
12946                                         bool            has_notnull = (tbinfo->notnull[j] &&
12947                                                                                            (!tbinfo->inhNotNull[j] ||
12948                                                                                                 binary_upgrade));
12949
12950                                         /* Skip column if fully defined by reloftype */
12951                                         if (tbinfo->reloftype &&
12952                                                 !has_default && !has_notnull && !binary_upgrade)
12953                                                 continue;
12954
12955                                         /* Format properly if not first attr */
12956                                         if (actual_atts == 0)
12957                                                 appendPQExpBuffer(q, " (");
12958                                         else
12959                                                 appendPQExpBuffer(q, ",");
12960                                         appendPQExpBuffer(q, "\n    ");
12961                                         actual_atts++;
12962
12963                                         /* Attribute name */
12964                                         appendPQExpBuffer(q, "%s",
12965                                                                           fmtId(tbinfo->attnames[j]));
12966
12967                                         if (tbinfo->attisdropped[j])
12968                                         {
12969                                                 /*
12970                                                  * ALTER TABLE DROP COLUMN clears
12971                                                  * pg_attribute.atttypid, so we will not have gotten a
12972                                                  * valid type name; insert INTEGER as a stopgap. We'll
12973                                                  * clean things up later.
12974                                                  */
12975                                                 appendPQExpBuffer(q, " INTEGER /* dummy */");
12976                                                 /* Skip all the rest, too */
12977                                                 continue;
12978                                         }
12979
12980                                         /* Attribute type */
12981                                         if (tbinfo->reloftype && !binary_upgrade)
12982                                         {
12983                                                 appendPQExpBuffer(q, " WITH OPTIONS");
12984                                         }
12985                                         else if (fout->remoteVersion >= 70100)
12986                                         {
12987                                                 appendPQExpBuffer(q, " %s",
12988                                                                                   tbinfo->atttypnames[j]);
12989                                         }
12990                                         else
12991                                         {
12992                                                 /* If no format_type, fake it */
12993                                                 appendPQExpBuffer(q, " %s",
12994                                                                                   myFormatType(tbinfo->atttypnames[j],
12995                                                                                                            tbinfo->atttypmod[j]));
12996                                         }
12997
12998                                         /* Add collation if not default for the type */
12999                                         if (OidIsValid(tbinfo->attcollation[j]))
13000                                         {
13001                                                 CollInfo   *coll;
13002
13003                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
13004                                                 if (coll)
13005                                                 {
13006                                                         /* always schema-qualify, don't try to be smart */
13007                                                         appendPQExpBuffer(q, " COLLATE %s.",
13008                                                                          fmtId(coll->dobj.namespace->dobj.name));
13009                                                         appendPQExpBuffer(q, "%s",
13010                                                                                           fmtId(coll->dobj.name));
13011                                                 }
13012                                         }
13013
13014                                         if (has_default)
13015                                                 appendPQExpBuffer(q, " DEFAULT %s",
13016                                                                                   tbinfo->attrdefs[j]->adef_expr);
13017
13018                                         if (has_notnull)
13019                                                 appendPQExpBuffer(q, " NOT NULL");
13020                                 }
13021                         }
13022
13023                         /*
13024                          * Add non-inherited CHECK constraints, if any.
13025                          */
13026                         for (j = 0; j < tbinfo->ncheck; j++)
13027                         {
13028                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13029
13030                                 if (constr->separate || !constr->conislocal)
13031                                         continue;
13032
13033                                 if (actual_atts == 0)
13034                                         appendPQExpBuffer(q, " (\n    ");
13035                                 else
13036                                         appendPQExpBuffer(q, ",\n    ");
13037
13038                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13039                                                                   fmtId(constr->dobj.name));
13040                                 appendPQExpBuffer(q, "%s", constr->condef);
13041
13042                                 actual_atts++;
13043                         }
13044
13045                         if (actual_atts)
13046                                 appendPQExpBuffer(q, "\n)");
13047                         else if (!(tbinfo->reloftype && !binary_upgrade))
13048                         {
13049                                 /*
13050                                  * We must have a parenthesized attribute list, even though
13051                                  * empty, when not using the OF TYPE syntax.
13052                                  */
13053                                 appendPQExpBuffer(q, " (\n)");
13054                         }
13055
13056                         if (numParents > 0 && !binary_upgrade)
13057                         {
13058                                 appendPQExpBuffer(q, "\nINHERITS (");
13059                                 for (k = 0; k < numParents; k++)
13060                                 {
13061                                         TableInfo  *parentRel = parents[k];
13062
13063                                         if (k > 0)
13064                                                 appendPQExpBuffer(q, ", ");
13065                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13066                                                 appendPQExpBuffer(q, "%s.",
13067                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13068                                         appendPQExpBuffer(q, "%s",
13069                                                                           fmtId(parentRel->dobj.name));
13070                                 }
13071                                 appendPQExpBuffer(q, ")");
13072                         }
13073
13074                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13075                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13076                 }
13077
13078                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13079                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13080                 {
13081                         bool            addcomma = false;
13082
13083                         appendPQExpBuffer(q, "\nWITH (");
13084                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13085                         {
13086                                 addcomma = true;
13087                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
13088                         }
13089                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13090                         {
13091                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13092                                                                   tbinfo->toast_reloptions);
13093                         }
13094                         appendPQExpBuffer(q, ")");
13095                 }
13096
13097                 /* Dump generic options if any */
13098                 if (ftoptions && ftoptions[0])
13099                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13100
13101                 /*
13102                  * For materialized views, create the AS clause just like a view.
13103                  */
13104                 if (tbinfo->relkind == RELKIND_MATVIEW)
13105                 {
13106                         PQExpBuffer result;
13107
13108                         result = createViewAsClause(fout, tbinfo);
13109                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13110                                                           result->data);
13111                         destroyPQExpBuffer(result);
13112                 }
13113                 else
13114                         appendPQExpBuffer(q, ";\n");
13115
13116                 /*
13117                  * To create binary-compatible heap files, we have to ensure the same
13118                  * physical column order, including dropped columns, as in the
13119                  * original.  Therefore, we create dropped columns above and drop them
13120                  * here, also updating their attlen/attalign values so that the
13121                  * dropped column can be skipped properly.      (We do not bother with
13122                  * restoring the original attbyval setting.)  Also, inheritance
13123                  * relationships are set up by doing ALTER INHERIT rather than using
13124                  * an INHERITS clause --- the latter would possibly mess up the column
13125                  * order.  That also means we have to take care about setting
13126                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13127                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13128                  */
13129                 if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
13130                 {
13131                         for (j = 0; j < tbinfo->numatts; j++)
13132                         {
13133                                 if (tbinfo->attisdropped[j])
13134                                 {
13135                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
13136                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13137                                                                           "SET attlen = %d, "
13138                                                                           "attalign = '%c', attbyval = false\n"
13139                                                                           "WHERE attname = ",
13140                                                                           tbinfo->attlen[j],
13141                                                                           tbinfo->attalign[j]);
13142                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13143                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13144                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13145                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13146
13147                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13148                                                                           fmtId(tbinfo->dobj.name));
13149                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13150                                                                           fmtId(tbinfo->attnames[j]));
13151                                 }
13152                                 else if (!tbinfo->attislocal[j])
13153                                 {
13154                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
13155                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13156                                                                           "SET attislocal = false\n"
13157                                                                           "WHERE attname = ");
13158                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13159                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13160                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13161                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13162                                 }
13163                         }
13164
13165                         for (k = 0; k < tbinfo->ncheck; k++)
13166                         {
13167                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13168
13169                                 if (constr->separate || constr->conislocal)
13170                                         continue;
13171
13172                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13173                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13174                                                                   fmtId(tbinfo->dobj.name));
13175                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13176                                                                   fmtId(constr->dobj.name));
13177                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13178                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
13179                                                                   "SET conislocal = false\n"
13180                                                                   "WHERE contype = 'c' AND conname = ");
13181                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13182                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
13183                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13184                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13185                         }
13186
13187                         if (numParents > 0)
13188                         {
13189                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13190                                 for (k = 0; k < numParents; k++)
13191                                 {
13192                                         TableInfo  *parentRel = parents[k];
13193
13194                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13195                                                                           fmtId(tbinfo->dobj.name));
13196                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13197                                                 appendPQExpBuffer(q, "%s.",
13198                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13199                                         appendPQExpBuffer(q, "%s;\n",
13200                                                                           fmtId(parentRel->dobj.name));
13201                                 }
13202                         }
13203
13204                         if (tbinfo->reloftype)
13205                         {
13206                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13207                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13208                                                                   fmtId(tbinfo->dobj.name),
13209                                                                   tbinfo->reloftype);
13210                         }
13211
13212                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13213                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13214                                                           "SET relfrozenxid = '%u'\n"
13215                                                           "WHERE oid = ",
13216                                                           tbinfo->frozenxid);
13217                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13218                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13219
13220                         if (tbinfo->toast_oid)
13221                         {
13222                                 /* We preserve the toast oids, so we can use it during restore */
13223                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13224                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13225                                                                   "SET relfrozenxid = '%u'\n"
13226                                                                   "WHERE oid = '%u';\n",
13227                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13228                         }
13229                 }
13230
13231                 /*
13232                  * Dump additional per-column properties that we can't handle in the
13233                  * main CREATE TABLE command.
13234                  */
13235                 for (j = 0; j < tbinfo->numatts; j++)
13236                 {
13237                         /* None of this applies to dropped columns */
13238                         if (tbinfo->attisdropped[j])
13239                                 continue;
13240
13241                         /*
13242                          * If we didn't dump the column definition explicitly above, and
13243                          * it is NOT NULL and did not inherit that property from a parent,
13244                          * we have to mark it separately.
13245                          */
13246                         if (!shouldPrintColumn(tbinfo, j) &&
13247                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13248                         {
13249                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13250                                                                   fmtId(tbinfo->dobj.name));
13251                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13252                                                                   fmtId(tbinfo->attnames[j]));
13253                         }
13254
13255                         /*
13256                          * Dump per-column statistics information. We only issue an ALTER
13257                          * TABLE statement if the attstattarget entry for this column is
13258                          * non-negative (i.e. it's not the default value)
13259                          */
13260                         if (tbinfo->attstattarget[j] >= 0)
13261                         {
13262                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13263                                                                   fmtId(tbinfo->dobj.name));
13264                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13265                                                                   fmtId(tbinfo->attnames[j]));
13266                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13267                                                                   tbinfo->attstattarget[j]);
13268                         }
13269
13270                         /*
13271                          * Dump per-column storage information.  The statement is only
13272                          * dumped if the storage has been changed from the type's default.
13273                          */
13274                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13275                         {
13276                                 switch (tbinfo->attstorage[j])
13277                                 {
13278                                         case 'p':
13279                                                 storage = "PLAIN";
13280                                                 break;
13281                                         case 'e':
13282                                                 storage = "EXTERNAL";
13283                                                 break;
13284                                         case 'm':
13285                                                 storage = "MAIN";
13286                                                 break;
13287                                         case 'x':
13288                                                 storage = "EXTENDED";
13289                                                 break;
13290                                         default:
13291                                                 storage = NULL;
13292                                 }
13293
13294                                 /*
13295                                  * Only dump the statement if it's a storage type we recognize
13296                                  */
13297                                 if (storage != NULL)
13298                                 {
13299                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13300                                                                           fmtId(tbinfo->dobj.name));
13301                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
13302                                                                           fmtId(tbinfo->attnames[j]));
13303                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
13304                                                                           storage);
13305                                 }
13306                         }
13307
13308                         /*
13309                          * Dump per-column attributes.
13310                          */
13311                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13312                         {
13313                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13314                                                                   fmtId(tbinfo->dobj.name));
13315                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13316                                                                   fmtId(tbinfo->attnames[j]));
13317                                 appendPQExpBuffer(q, "SET (%s);\n",
13318                                                                   tbinfo->attoptions[j]);
13319                         }
13320
13321                         /*
13322                          * Dump per-column fdw options.
13323                          */
13324                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13325                                 tbinfo->attfdwoptions[j] &&
13326                                 tbinfo->attfdwoptions[j][0] != '\0')
13327                         {
13328                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13329                                                                   fmtId(tbinfo->dobj.name));
13330                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13331                                                                   fmtId(tbinfo->attnames[j]));
13332                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13333                                                                   tbinfo->attfdwoptions[j]);
13334                         }
13335                 }
13336         }
13337
13338         if (binary_upgrade)
13339                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13340
13341         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13342                                  tbinfo->dobj.name,
13343                                  tbinfo->dobj.namespace->dobj.name,
13344                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13345                                  tbinfo->rolname,
13346                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13347                                  reltypename, SECTION_PRE_DATA,
13348                                  q->data, delq->data, NULL,
13349                                  NULL, 0,
13350                                  NULL, NULL);
13351
13352
13353         /* Dump Table Comments */
13354         dumpTableComment(fout, tbinfo, reltypename);
13355
13356         /* Dump Table Security Labels */
13357         dumpTableSecLabel(fout, tbinfo, reltypename);
13358
13359         /* Dump comments on inlined table constraints */
13360         for (j = 0; j < tbinfo->ncheck; j++)
13361         {
13362                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13363
13364                 if (constr->separate || !constr->conislocal)
13365                         continue;
13366
13367                 dumpTableConstraintComment(fout, constr);
13368         }
13369
13370         destroyPQExpBuffer(q);
13371         destroyPQExpBuffer(delq);
13372         destroyPQExpBuffer(labelq);
13373 }
13374
13375 /*
13376  * dumpAttrDef --- dump an attribute's default-value declaration
13377  */
13378 static void
13379 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13380 {
13381         TableInfo  *tbinfo = adinfo->adtable;
13382         int                     adnum = adinfo->adnum;
13383         PQExpBuffer q;
13384         PQExpBuffer delq;
13385
13386         /* Skip if table definition not to be dumped */
13387         if (!tbinfo->dobj.dump || dataOnly)
13388                 return;
13389
13390         /* Skip if not "separate"; it was dumped in the table's definition */
13391         if (!adinfo->separate)
13392                 return;
13393
13394         q = createPQExpBuffer();
13395         delq = createPQExpBuffer();
13396
13397         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13398                                           fmtId(tbinfo->dobj.name));
13399         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13400                                           fmtId(tbinfo->attnames[adnum - 1]),
13401                                           adinfo->adef_expr);
13402
13403         /*
13404          * DROP must be fully qualified in case same name appears in pg_catalog
13405          */
13406         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13407                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13408         appendPQExpBuffer(delq, "%s ",
13409                                           fmtId(tbinfo->dobj.name));
13410         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13411                                           fmtId(tbinfo->attnames[adnum - 1]));
13412
13413         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13414                                  tbinfo->attnames[adnum - 1],
13415                                  tbinfo->dobj.namespace->dobj.name,
13416                                  NULL,
13417                                  tbinfo->rolname,
13418                                  false, "DEFAULT", SECTION_PRE_DATA,
13419                                  q->data, delq->data, NULL,
13420                                  NULL, 0,
13421                                  NULL, NULL);
13422
13423         destroyPQExpBuffer(q);
13424         destroyPQExpBuffer(delq);
13425 }
13426
13427 /*
13428  * getAttrName: extract the correct name for an attribute
13429  *
13430  * The array tblInfo->attnames[] only provides names of user attributes;
13431  * if a system attribute number is supplied, we have to fake it.
13432  * We also do a little bit of bounds checking for safety's sake.
13433  */
13434 static const char *
13435 getAttrName(int attrnum, TableInfo *tblInfo)
13436 {
13437         if (attrnum > 0 && attrnum <= tblInfo->numatts)
13438                 return tblInfo->attnames[attrnum - 1];
13439         switch (attrnum)
13440         {
13441                 case SelfItemPointerAttributeNumber:
13442                         return "ctid";
13443                 case ObjectIdAttributeNumber:
13444                         return "oid";
13445                 case MinTransactionIdAttributeNumber:
13446                         return "xmin";
13447                 case MinCommandIdAttributeNumber:
13448                         return "cmin";
13449                 case MaxTransactionIdAttributeNumber:
13450                         return "xmax";
13451                 case MaxCommandIdAttributeNumber:
13452                         return "cmax";
13453                 case TableOidAttributeNumber:
13454                         return "tableoid";
13455         }
13456         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13457                                   attrnum, tblInfo->dobj.name);
13458         return NULL;                            /* keep compiler quiet */
13459 }
13460
13461 /*
13462  * dumpIndex
13463  *        write out to fout a user-defined index
13464  */
13465 static void
13466 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13467 {
13468         TableInfo  *tbinfo = indxinfo->indextable;
13469         PQExpBuffer q;
13470         PQExpBuffer delq;
13471         PQExpBuffer labelq;
13472
13473         if (dataOnly)
13474                 return;
13475
13476         q = createPQExpBuffer();
13477         delq = createPQExpBuffer();
13478         labelq = createPQExpBuffer();
13479
13480         appendPQExpBuffer(labelq, "INDEX %s",
13481                                           fmtId(indxinfo->dobj.name));
13482
13483         /*
13484          * If there's an associated constraint, don't dump the index per se, but
13485          * do dump any comment for it.  (This is safe because dependency ordering
13486          * will have ensured the constraint is emitted first.)
13487          */
13488         if (indxinfo->indexconstraint == 0)
13489         {
13490                 if (binary_upgrade)
13491                         binary_upgrade_set_pg_class_oids(fout, q,
13492                                                                                          indxinfo->dobj.catId.oid, true);
13493
13494                 /* Plain secondary index */
13495                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13496
13497                 /* If the index is clustered, we need to record that. */
13498                 if (indxinfo->indisclustered)
13499                 {
13500                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13501                                                           fmtId(tbinfo->dobj.name));
13502                         appendPQExpBuffer(q, " ON %s;\n",
13503                                                           fmtId(indxinfo->dobj.name));
13504                 }
13505
13506                 /*
13507                  * DROP must be fully qualified in case same name appears in
13508                  * pg_catalog
13509                  */
13510                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13511                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13512                 appendPQExpBuffer(delq, "%s;\n",
13513                                                   fmtId(indxinfo->dobj.name));
13514
13515                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13516                                          indxinfo->dobj.name,
13517                                          tbinfo->dobj.namespace->dobj.name,
13518                                          indxinfo->tablespace,
13519                                          tbinfo->rolname, false,
13520                                          "INDEX", SECTION_POST_DATA,
13521                                          q->data, delq->data, NULL,
13522                                          NULL, 0,
13523                                          NULL, NULL);
13524         }
13525
13526         /* Dump Index Comments */
13527         dumpComment(fout, labelq->data,
13528                                 tbinfo->dobj.namespace->dobj.name,
13529                                 tbinfo->rolname,
13530                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
13531
13532         destroyPQExpBuffer(q);
13533         destroyPQExpBuffer(delq);
13534         destroyPQExpBuffer(labelq);
13535 }
13536
13537 /*
13538  * dumpConstraint
13539  *        write out to fout a user-defined constraint
13540  */
13541 static void
13542 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13543 {
13544         TableInfo  *tbinfo = coninfo->contable;
13545         PQExpBuffer q;
13546         PQExpBuffer delq;
13547
13548         /* Skip if not to be dumped */
13549         if (!coninfo->dobj.dump || dataOnly)
13550                 return;
13551
13552         q = createPQExpBuffer();
13553         delq = createPQExpBuffer();
13554
13555         if (coninfo->contype == 'p' ||
13556                 coninfo->contype == 'u' ||
13557                 coninfo->contype == 'x')
13558         {
13559                 /* Index-related constraint */
13560                 IndxInfo   *indxinfo;
13561                 int                     k;
13562
13563                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13564
13565                 if (indxinfo == NULL)
13566                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13567                                                   coninfo->dobj.name);
13568
13569                 if (binary_upgrade)
13570                         binary_upgrade_set_pg_class_oids(fout, q,
13571                                                                                          indxinfo->dobj.catId.oid, true);
13572
13573                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13574                                                   fmtId(tbinfo->dobj.name));
13575                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13576                                                   fmtId(coninfo->dobj.name));
13577
13578                 if (coninfo->condef)
13579                 {
13580                         /* pg_get_constraintdef should have provided everything */
13581                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13582                 }
13583                 else
13584                 {
13585                         appendPQExpBuffer(q, "%s (",
13586                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13587                         for (k = 0; k < indxinfo->indnkeys; k++)
13588                         {
13589                                 int                     indkey = (int) indxinfo->indkeys[k];
13590                                 const char *attname;
13591
13592                                 if (indkey == InvalidAttrNumber)
13593                                         break;
13594                                 attname = getAttrName(indkey, tbinfo);
13595
13596                                 appendPQExpBuffer(q, "%s%s",
13597                                                                   (k == 0) ? "" : ", ",
13598                                                                   fmtId(attname));
13599                         }
13600
13601                         appendPQExpBuffer(q, ")");
13602
13603                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13604                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13605
13606                         if (coninfo->condeferrable)
13607                         {
13608                                 appendPQExpBuffer(q, " DEFERRABLE");
13609                                 if (coninfo->condeferred)
13610                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13611                         }
13612
13613                         appendPQExpBuffer(q, ";\n");
13614                 }
13615
13616                 /* If the index is clustered, we need to record that. */
13617                 if (indxinfo->indisclustered)
13618                 {
13619                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13620                                                           fmtId(tbinfo->dobj.name));
13621                         appendPQExpBuffer(q, " ON %s;\n",
13622                                                           fmtId(indxinfo->dobj.name));
13623                 }
13624
13625                 /*
13626                  * DROP must be fully qualified in case same name appears in
13627                  * pg_catalog
13628                  */
13629                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13630                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13631                 appendPQExpBuffer(delq, "%s ",
13632                                                   fmtId(tbinfo->dobj.name));
13633                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13634                                                   fmtId(coninfo->dobj.name));
13635
13636                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13637                                          coninfo->dobj.name,
13638                                          tbinfo->dobj.namespace->dobj.name,
13639                                          indxinfo->tablespace,
13640                                          tbinfo->rolname, false,
13641                                          "CONSTRAINT", SECTION_POST_DATA,
13642                                          q->data, delq->data, NULL,
13643                                          NULL, 0,
13644                                          NULL, NULL);
13645         }
13646         else if (coninfo->contype == 'f')
13647         {
13648                 /*
13649                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13650                  * current table data is not processed
13651                  */
13652                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13653                                                   fmtId(tbinfo->dobj.name));
13654                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13655                                                   fmtId(coninfo->dobj.name),
13656                                                   coninfo->condef);
13657
13658                 /*
13659                  * DROP must be fully qualified in case same name appears in
13660                  * pg_catalog
13661                  */
13662                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13663                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13664                 appendPQExpBuffer(delq, "%s ",
13665                                                   fmtId(tbinfo->dobj.name));
13666                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13667                                                   fmtId(coninfo->dobj.name));
13668
13669                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13670                                          coninfo->dobj.name,
13671                                          tbinfo->dobj.namespace->dobj.name,
13672                                          NULL,
13673                                          tbinfo->rolname, false,
13674                                          "FK CONSTRAINT", SECTION_POST_DATA,
13675                                          q->data, delq->data, NULL,
13676                                          NULL, 0,
13677                                          NULL, NULL);
13678         }
13679         else if (coninfo->contype == 'c' && tbinfo)
13680         {
13681                 /* CHECK constraint on a table */
13682
13683                 /* Ignore if not to be dumped separately */
13684                 if (coninfo->separate)
13685                 {
13686                         /* not ONLY since we want it to propagate to children */
13687                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13688                                                           fmtId(tbinfo->dobj.name));
13689                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13690                                                           fmtId(coninfo->dobj.name),
13691                                                           coninfo->condef);
13692
13693                         /*
13694                          * DROP must be fully qualified in case same name appears in
13695                          * pg_catalog
13696                          */
13697                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13698                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13699                         appendPQExpBuffer(delq, "%s ",
13700                                                           fmtId(tbinfo->dobj.name));
13701                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13702                                                           fmtId(coninfo->dobj.name));
13703
13704                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13705                                                  coninfo->dobj.name,
13706                                                  tbinfo->dobj.namespace->dobj.name,
13707                                                  NULL,
13708                                                  tbinfo->rolname, false,
13709                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13710                                                  q->data, delq->data, NULL,
13711                                                  NULL, 0,
13712                                                  NULL, NULL);
13713                 }
13714         }
13715         else if (coninfo->contype == 'c' && tbinfo == NULL)
13716         {
13717                 /* CHECK constraint on a domain */
13718                 TypeInfo   *tyinfo = coninfo->condomain;
13719
13720                 /* Ignore if not to be dumped separately */
13721                 if (coninfo->separate)
13722                 {
13723                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13724                                                           fmtId(tyinfo->dobj.name));
13725                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13726                                                           fmtId(coninfo->dobj.name),
13727                                                           coninfo->condef);
13728
13729                         /*
13730                          * DROP must be fully qualified in case same name appears in
13731                          * pg_catalog
13732                          */
13733                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13734                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13735                         appendPQExpBuffer(delq, "%s ",
13736                                                           fmtId(tyinfo->dobj.name));
13737                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13738                                                           fmtId(coninfo->dobj.name));
13739
13740                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13741                                                  coninfo->dobj.name,
13742                                                  tyinfo->dobj.namespace->dobj.name,
13743                                                  NULL,
13744                                                  tyinfo->rolname, false,
13745                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13746                                                  q->data, delq->data, NULL,
13747                                                  NULL, 0,
13748                                                  NULL, NULL);
13749                 }
13750         }
13751         else
13752         {
13753                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
13754                                           coninfo->contype);
13755         }
13756
13757         /* Dump Constraint Comments --- only works for table constraints */
13758         if (tbinfo && coninfo->separate)
13759                 dumpTableConstraintComment(fout, coninfo);
13760
13761         destroyPQExpBuffer(q);
13762         destroyPQExpBuffer(delq);
13763 }
13764
13765 /*
13766  * dumpTableConstraintComment --- dump a constraint's comment if any
13767  *
13768  * This is split out because we need the function in two different places
13769  * depending on whether the constraint is dumped as part of CREATE TABLE
13770  * or as a separate ALTER command.
13771  */
13772 static void
13773 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13774 {
13775         TableInfo  *tbinfo = coninfo->contable;
13776         PQExpBuffer labelq = createPQExpBuffer();
13777
13778         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13779                                           fmtId(coninfo->dobj.name));
13780         appendPQExpBuffer(labelq, "ON %s",
13781                                           fmtId(tbinfo->dobj.name));
13782         dumpComment(fout, labelq->data,
13783                                 tbinfo->dobj.namespace->dobj.name,
13784                                 tbinfo->rolname,
13785                                 coninfo->dobj.catId, 0,
13786                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13787
13788         destroyPQExpBuffer(labelq);
13789 }
13790
13791 /*
13792  * findLastBuiltInOid -
13793  * find the last built in oid
13794  *
13795  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13796  * pg_database entry for the current database
13797  */
13798 static Oid
13799 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
13800 {
13801         PGresult   *res;
13802         Oid                     last_oid;
13803         PQExpBuffer query = createPQExpBuffer();
13804
13805         resetPQExpBuffer(query);
13806         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13807         appendStringLiteralAH(query, dbname, fout);
13808
13809         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13810         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13811         PQclear(res);
13812         destroyPQExpBuffer(query);
13813         return last_oid;
13814 }
13815
13816 /*
13817  * findLastBuiltInOid -
13818  * find the last built in oid
13819  *
13820  * For 7.0, we do this by assuming that the last thing that initdb does is to
13821  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13822  * initdb won't be changing anymore, it'll do.
13823  */
13824 static Oid
13825 findLastBuiltinOid_V70(Archive *fout)
13826 {
13827         PGresult   *res;
13828         int                     last_oid;
13829
13830         res = ExecuteSqlQueryForSingleRow(fout,
13831                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13832         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13833         PQclear(res);
13834         return last_oid;
13835 }
13836
13837 /*
13838  * dumpSequence
13839  *        write the declaration (not data) of one user-defined sequence
13840  */
13841 static void
13842 dumpSequence(Archive *fout, TableInfo *tbinfo)
13843 {
13844         PGresult   *res;
13845         char       *startv,
13846                            *incby,
13847                            *maxv = NULL,
13848                            *minv = NULL,
13849                            *cache;
13850         char            bufm[100],
13851                                 bufx[100];
13852         bool            cycled;
13853         PQExpBuffer query = createPQExpBuffer();
13854         PQExpBuffer delqry = createPQExpBuffer();
13855         PQExpBuffer labelq = createPQExpBuffer();
13856
13857         /* Make sure we are in proper schema */
13858         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13859
13860         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13861         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13862
13863         if (fout->remoteVersion >= 80400)
13864         {
13865                 appendPQExpBuffer(query,
13866                                                   "SELECT sequence_name, "
13867                                                   "start_value, increment_by, "
13868                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13869                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13870                                                   "     ELSE max_value "
13871                                                   "END AS max_value, "
13872                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13873                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13874                                                   "     ELSE min_value "
13875                                                   "END AS min_value, "
13876                                                   "cache_value, is_cycled FROM %s",
13877                                                   bufx, bufm,
13878                                                   fmtId(tbinfo->dobj.name));
13879         }
13880         else
13881         {
13882                 appendPQExpBuffer(query,
13883                                                   "SELECT sequence_name, "
13884                                                   "0 AS start_value, increment_by, "
13885                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13886                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13887                                                   "     ELSE max_value "
13888                                                   "END AS max_value, "
13889                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13890                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13891                                                   "     ELSE min_value "
13892                                                   "END AS min_value, "
13893                                                   "cache_value, is_cycled FROM %s",
13894                                                   bufx, bufm,
13895                                                   fmtId(tbinfo->dobj.name));
13896         }
13897
13898         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13899
13900         if (PQntuples(res) != 1)
13901         {
13902                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13903                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13904                                                                  PQntuples(res)),
13905                                   tbinfo->dobj.name, PQntuples(res));
13906                 exit_nicely(1);
13907         }
13908
13909         /* Disable this check: it fails if sequence has been renamed */
13910 #ifdef NOT_USED
13911         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13912         {
13913                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13914                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13915                 exit_nicely(1);
13916         }
13917 #endif
13918
13919         startv = PQgetvalue(res, 0, 1);
13920         incby = PQgetvalue(res, 0, 2);
13921         if (!PQgetisnull(res, 0, 3))
13922                 maxv = PQgetvalue(res, 0, 3);
13923         if (!PQgetisnull(res, 0, 4))
13924                 minv = PQgetvalue(res, 0, 4);
13925         cache = PQgetvalue(res, 0, 5);
13926         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
13927
13928         /*
13929          * DROP must be fully qualified in case same name appears in pg_catalog
13930          */
13931         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13932                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13933         appendPQExpBuffer(delqry, "%s;\n",
13934                                           fmtId(tbinfo->dobj.name));
13935
13936         resetPQExpBuffer(query);
13937
13938         if (binary_upgrade)
13939         {
13940                 binary_upgrade_set_pg_class_oids(fout, query,
13941                                                                                  tbinfo->dobj.catId.oid, false);
13942                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
13943                                                                                                 tbinfo->dobj.catId.oid);
13944         }
13945
13946         appendPQExpBuffer(query,
13947                                           "CREATE SEQUENCE %s\n",
13948                                           fmtId(tbinfo->dobj.name));
13949
13950         if (fout->remoteVersion >= 80400)
13951                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
13952
13953         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13954
13955         if (minv)
13956                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13957         else
13958                 appendPQExpBuffer(query, "    NO MINVALUE\n");
13959
13960         if (maxv)
13961                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13962         else
13963                 appendPQExpBuffer(query, "    NO MAXVALUE\n");
13964
13965         appendPQExpBuffer(query,
13966                                           "    CACHE %s%s",
13967                                           cache, (cycled ? "\n    CYCLE" : ""));
13968
13969         appendPQExpBuffer(query, ";\n");
13970
13971         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13972
13973         /* binary_upgrade:      no need to clear TOAST table oid */
13974
13975         if (binary_upgrade)
13976                 binary_upgrade_extension_member(query, &tbinfo->dobj,
13977                                                                                 labelq->data);
13978
13979         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13980                                  tbinfo->dobj.name,
13981                                  tbinfo->dobj.namespace->dobj.name,
13982                                  NULL,
13983                                  tbinfo->rolname,
13984                                  false, "SEQUENCE", SECTION_PRE_DATA,
13985                                  query->data, delqry->data, NULL,
13986                                  NULL, 0,
13987                                  NULL, NULL);
13988
13989         /*
13990          * If the sequence is owned by a table column, emit the ALTER for it as a
13991          * separate TOC entry immediately following the sequence's own entry. It's
13992          * OK to do this rather than using full sorting logic, because the
13993          * dependency that tells us it's owned will have forced the table to be
13994          * created first.  We can't just include the ALTER in the TOC entry
13995          * because it will fail if we haven't reassigned the sequence owner to
13996          * match the table's owner.
13997          *
13998          * We need not schema-qualify the table reference because both sequence
13999          * and table must be in the same schema.
14000          */
14001         if (OidIsValid(tbinfo->owning_tab))
14002         {
14003                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14004
14005                 if (owning_tab && owning_tab->dobj.dump)
14006                 {
14007                         resetPQExpBuffer(query);
14008                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14009                                                           fmtId(tbinfo->dobj.name));
14010                         appendPQExpBuffer(query, " OWNED BY %s",
14011                                                           fmtId(owning_tab->dobj.name));
14012                         appendPQExpBuffer(query, ".%s;\n",
14013                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14014
14015                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14016                                                  tbinfo->dobj.name,
14017                                                  tbinfo->dobj.namespace->dobj.name,
14018                                                  NULL,
14019                                                  tbinfo->rolname,
14020                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14021                                                  query->data, "", NULL,
14022                                                  &(tbinfo->dobj.dumpId), 1,
14023                                                  NULL, NULL);
14024                 }
14025         }
14026
14027         /* Dump Sequence Comments and Security Labels */
14028         dumpComment(fout, labelq->data,
14029                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14030                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14031         dumpSecLabel(fout, labelq->data,
14032                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14033                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14034
14035         PQclear(res);
14036
14037         destroyPQExpBuffer(query);
14038         destroyPQExpBuffer(delqry);
14039         destroyPQExpBuffer(labelq);
14040 }
14041
14042 /*
14043  * dumpSequenceData
14044  *        write the data of one user-defined sequence
14045  */
14046 static void
14047 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14048 {
14049         TableInfo  *tbinfo = tdinfo->tdtable;
14050         PGresult   *res;
14051         char       *last;
14052         bool            called;
14053         PQExpBuffer query = createPQExpBuffer();
14054
14055         /* Make sure we are in proper schema */
14056         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14057
14058         appendPQExpBuffer(query,
14059                                           "SELECT last_value, is_called FROM %s",
14060                                           fmtId(tbinfo->dobj.name));
14061
14062         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14063
14064         if (PQntuples(res) != 1)
14065         {
14066                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14067                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14068                                                                  PQntuples(res)),
14069                                   tbinfo->dobj.name, PQntuples(res));
14070                 exit_nicely(1);
14071         }
14072
14073         last = PQgetvalue(res, 0, 0);
14074         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14075
14076         resetPQExpBuffer(query);
14077         appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
14078         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14079         appendPQExpBuffer(query, ", %s, %s);\n",
14080                                           last, (called ? "true" : "false"));
14081
14082         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14083                                  tbinfo->dobj.name,
14084                                  tbinfo->dobj.namespace->dobj.name,
14085                                  NULL,
14086                                  tbinfo->rolname,
14087                                  false, "SEQUENCE SET", SECTION_DATA,
14088                                  query->data, "", NULL,
14089                                  &(tbinfo->dobj.dumpId), 1,
14090                                  NULL, NULL);
14091
14092         PQclear(res);
14093
14094         destroyPQExpBuffer(query);
14095 }
14096
14097 static void
14098 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14099 {
14100         TableInfo  *tbinfo = tginfo->tgtable;
14101         PQExpBuffer query;
14102         PQExpBuffer delqry;
14103         PQExpBuffer labelq;
14104         char       *tgargs;
14105         size_t          lentgargs;
14106         const char *p;
14107         int                     findx;
14108
14109         if (dataOnly)
14110                 return;
14111
14112         query = createPQExpBuffer();
14113         delqry = createPQExpBuffer();
14114         labelq = createPQExpBuffer();
14115
14116         /*
14117          * DROP must be fully qualified in case same name appears in pg_catalog
14118          */
14119         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14120                                           fmtId(tginfo->dobj.name));
14121         appendPQExpBuffer(delqry, "ON %s.",
14122                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14123         appendPQExpBuffer(delqry, "%s;\n",
14124                                           fmtId(tbinfo->dobj.name));
14125
14126         if (tginfo->tgdef)
14127         {
14128                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14129         }
14130         else
14131         {
14132                 if (tginfo->tgisconstraint)
14133                 {
14134                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
14135                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14136                 }
14137                 else
14138                 {
14139                         appendPQExpBuffer(query, "CREATE TRIGGER ");
14140                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14141                 }
14142                 appendPQExpBuffer(query, "\n    ");
14143
14144                 /* Trigger type */
14145                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14146                         appendPQExpBuffer(query, "BEFORE");
14147                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14148                         appendPQExpBuffer(query, "AFTER");
14149                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14150                         appendPQExpBuffer(query, "INSTEAD OF");
14151                 else
14152                 {
14153                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14154                         exit_nicely(1);
14155                 }
14156
14157                 findx = 0;
14158                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14159                 {
14160                         appendPQExpBuffer(query, " INSERT");
14161                         findx++;
14162                 }
14163                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14164                 {
14165                         if (findx > 0)
14166                                 appendPQExpBuffer(query, " OR DELETE");
14167                         else
14168                                 appendPQExpBuffer(query, " DELETE");
14169                         findx++;
14170                 }
14171                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14172                 {
14173                         if (findx > 0)
14174                                 appendPQExpBuffer(query, " OR UPDATE");
14175                         else
14176                                 appendPQExpBuffer(query, " UPDATE");
14177                         findx++;
14178                 }
14179                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14180                 {
14181                         if (findx > 0)
14182                                 appendPQExpBuffer(query, " OR TRUNCATE");
14183                         else
14184                                 appendPQExpBuffer(query, " TRUNCATE");
14185                         findx++;
14186                 }
14187                 appendPQExpBuffer(query, " ON %s\n",
14188                                                   fmtId(tbinfo->dobj.name));
14189
14190                 if (tginfo->tgisconstraint)
14191                 {
14192                         if (OidIsValid(tginfo->tgconstrrelid))
14193                         {
14194                                 /* If we are using regclass, name is already quoted */
14195                                 if (fout->remoteVersion >= 70300)
14196                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14197                                                                           tginfo->tgconstrrelname);
14198                                 else
14199                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14200                                                                           fmtId(tginfo->tgconstrrelname));
14201                         }
14202                         if (!tginfo->tgdeferrable)
14203                                 appendPQExpBuffer(query, "NOT ");
14204                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
14205                         if (tginfo->tginitdeferred)
14206                                 appendPQExpBuffer(query, "DEFERRED\n");
14207                         else
14208                                 appendPQExpBuffer(query, "IMMEDIATE\n");
14209                 }
14210
14211                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14212                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
14213                 else
14214                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
14215
14216                 /* In 7.3, result of regproc is already quoted */
14217                 if (fout->remoteVersion >= 70300)
14218                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14219                                                           tginfo->tgfname);
14220                 else
14221                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14222                                                           fmtId(tginfo->tgfname));
14223
14224                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14225                                                                                   &lentgargs);
14226                 p = tgargs;
14227                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14228                 {
14229                         /* find the embedded null that terminates this trigger argument */
14230                         size_t          tlen = strlen(p);
14231
14232                         if (p + tlen >= tgargs + lentgargs)
14233                         {
14234                                 /* hm, not found before end of bytea value... */
14235                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14236                                                   tginfo->tgargs,
14237                                                   tginfo->dobj.name,
14238                                                   tbinfo->dobj.name);
14239                                 exit_nicely(1);
14240                         }
14241
14242                         if (findx > 0)
14243                                 appendPQExpBuffer(query, ", ");
14244                         appendStringLiteralAH(query, p, fout);
14245                         p += tlen + 1;
14246                 }
14247                 free(tgargs);
14248                 appendPQExpBuffer(query, ");\n");
14249         }
14250
14251         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14252         {
14253                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
14254                                                   fmtId(tbinfo->dobj.name));
14255                 switch (tginfo->tgenabled)
14256                 {
14257                         case 'D':
14258                         case 'f':
14259                                 appendPQExpBuffer(query, "DISABLE");
14260                                 break;
14261                         case 'A':
14262                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14263                                 break;
14264                         case 'R':
14265                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14266                                 break;
14267                         default:
14268                                 appendPQExpBuffer(query, "ENABLE");
14269                                 break;
14270                 }
14271                 appendPQExpBuffer(query, " TRIGGER %s;\n",
14272                                                   fmtId(tginfo->dobj.name));
14273         }
14274
14275         appendPQExpBuffer(labelq, "TRIGGER %s ",
14276                                           fmtId(tginfo->dobj.name));
14277         appendPQExpBuffer(labelq, "ON %s",
14278                                           fmtId(tbinfo->dobj.name));
14279
14280         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14281                                  tginfo->dobj.name,
14282                                  tbinfo->dobj.namespace->dobj.name,
14283                                  NULL,
14284                                  tbinfo->rolname, false,
14285                                  "TRIGGER", SECTION_POST_DATA,
14286                                  query->data, delqry->data, NULL,
14287                                  NULL, 0,
14288                                  NULL, NULL);
14289
14290         dumpComment(fout, labelq->data,
14291                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14292                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14293
14294         destroyPQExpBuffer(query);
14295         destroyPQExpBuffer(delqry);
14296         destroyPQExpBuffer(labelq);
14297 }
14298
14299 static void
14300 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14301 {
14302         PQExpBuffer query;
14303         PQExpBuffer labelq;
14304
14305         query = createPQExpBuffer();
14306         labelq = createPQExpBuffer();
14307
14308         appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
14309         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14310         appendPQExpBuffer(query, " ON ");
14311         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14312         appendPQExpBufferStr(query, " ");
14313
14314         if (strcmp("", evtinfo->evttags) != 0)
14315         {
14316                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14317                 appendPQExpBufferStr(query, evtinfo->evttags);
14318                 appendPQExpBufferStr(query, ") ");
14319         }
14320
14321         appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
14322         appendPQExpBufferStr(query, evtinfo->evtfname);
14323         appendPQExpBuffer(query, "();\n");
14324
14325         if (evtinfo->evtenabled != 'O')
14326         {
14327                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14328                                                   fmtId(evtinfo->dobj.name));
14329                 switch (evtinfo->evtenabled)
14330                 {
14331                         case 'D':
14332                                 appendPQExpBuffer(query, "DISABLE");
14333                                 break;
14334                         case 'A':
14335                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14336                                 break;
14337                         case 'R':
14338                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14339                                 break;
14340                         default:
14341                                 appendPQExpBuffer(query, "ENABLE");
14342                                 break;
14343                 }
14344                 appendPQExpBuffer(query, ";\n");
14345         }
14346         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14347                                           fmtId(evtinfo->dobj.name));
14348
14349         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14350                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14351                                  "EVENT TRIGGER", SECTION_POST_DATA,
14352                                  query->data, "", NULL, NULL, 0, NULL, NULL);
14353
14354         dumpComment(fout, labelq->data,
14355                                 NULL, NULL,
14356                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14357
14358         destroyPQExpBuffer(query);
14359         destroyPQExpBuffer(labelq);
14360 }
14361
14362 /*
14363  * dumpRule
14364  *              Dump a rule
14365  */
14366 static void
14367 dumpRule(Archive *fout, RuleInfo *rinfo)
14368 {
14369         TableInfo  *tbinfo = rinfo->ruletable;
14370         PQExpBuffer query;
14371         PQExpBuffer cmd;
14372         PQExpBuffer delcmd;
14373         PQExpBuffer labelq;
14374         PGresult   *res;
14375
14376         /* Skip if not to be dumped */
14377         if (!rinfo->dobj.dump || dataOnly)
14378                 return;
14379
14380         /*
14381          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14382          * we do not want to dump it as a separate object.
14383          */
14384         if (!rinfo->separate)
14385                 return;
14386
14387         /*
14388          * Make sure we are in proper schema.
14389          */
14390         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14391
14392         query = createPQExpBuffer();
14393         cmd = createPQExpBuffer();
14394         delcmd = createPQExpBuffer();
14395         labelq = createPQExpBuffer();
14396
14397         if (fout->remoteVersion >= 70300)
14398         {
14399                 appendPQExpBuffer(query,
14400                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14401                                                   rinfo->dobj.catId.oid);
14402         }
14403         else
14404         {
14405                 /* Rule name was unique before 7.3 ... */
14406                 appendPQExpBuffer(query,
14407                                                   "SELECT pg_get_ruledef('%s') AS definition",
14408                                                   rinfo->dobj.name);
14409         }
14410
14411         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14412
14413         if (PQntuples(res) != 1)
14414         {
14415                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14416                                   rinfo->dobj.name, tbinfo->dobj.name);
14417                 exit_nicely(1);
14418         }
14419
14420         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14421
14422         /*
14423          * Add the command to alter the rules replication firing semantics if it
14424          * differs from the default.
14425          */
14426         if (rinfo->ev_enabled != 'O')
14427         {
14428                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14429                 switch (rinfo->ev_enabled)
14430                 {
14431                         case 'A':
14432                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14433                                                                   fmtId(rinfo->dobj.name));
14434                                 break;
14435                         case 'R':
14436                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14437                                                                   fmtId(rinfo->dobj.name));
14438                                 break;
14439                         case 'D':
14440                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14441                                                                   fmtId(rinfo->dobj.name));
14442                                 break;
14443                 }
14444         }
14445
14446         /*
14447          * Apply view's reloptions when its ON SELECT rule is separate.
14448          */
14449         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14450         {
14451                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14452                                                   fmtId(tbinfo->dobj.name),
14453                                                   rinfo->reloptions);
14454         }
14455
14456         /*
14457          * DROP must be fully qualified in case same name appears in pg_catalog
14458          */
14459         appendPQExpBuffer(delcmd, "DROP RULE %s ",
14460                                           fmtId(rinfo->dobj.name));
14461         appendPQExpBuffer(delcmd, "ON %s.",
14462                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14463         appendPQExpBuffer(delcmd, "%s;\n",
14464                                           fmtId(tbinfo->dobj.name));
14465
14466         appendPQExpBuffer(labelq, "RULE %s",
14467                                           fmtId(rinfo->dobj.name));
14468         appendPQExpBuffer(labelq, " ON %s",
14469                                           fmtId(tbinfo->dobj.name));
14470
14471         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14472                                  rinfo->dobj.name,
14473                                  tbinfo->dobj.namespace->dobj.name,
14474                                  NULL,
14475                                  tbinfo->rolname, false,
14476                                  "RULE", SECTION_POST_DATA,
14477                                  cmd->data, delcmd->data, NULL,
14478                                  NULL, 0,
14479                                  NULL, NULL);
14480
14481         /* Dump rule comments */
14482         dumpComment(fout, labelq->data,
14483                                 tbinfo->dobj.namespace->dobj.name,
14484                                 tbinfo->rolname,
14485                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14486
14487         PQclear(res);
14488
14489         destroyPQExpBuffer(query);
14490         destroyPQExpBuffer(cmd);
14491         destroyPQExpBuffer(delcmd);
14492         destroyPQExpBuffer(labelq);
14493 }
14494
14495 /*
14496  * getExtensionMembership --- obtain extension membership data
14497  */
14498 void
14499 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14500                                            int numExtensions)
14501 {
14502         PQExpBuffer query;
14503         PGresult   *res;
14504         int                     ntups,
14505                                 i;
14506         int                     i_classid,
14507                                 i_objid,
14508                                 i_refclassid,
14509                                 i_refobjid;
14510         DumpableObject *dobj,
14511                            *refdobj;
14512
14513         /* Nothing to do if no extensions */
14514         if (numExtensions == 0)
14515                 return;
14516
14517         /* Make sure we are in proper schema */
14518         selectSourceSchema(fout, "pg_catalog");
14519
14520         query = createPQExpBuffer();
14521
14522         /* refclassid constraint is redundant but may speed the search */
14523         appendPQExpBuffer(query, "SELECT "
14524                                           "classid, objid, refclassid, refobjid "
14525                                           "FROM pg_depend "
14526                                           "WHERE refclassid = 'pg_extension'::regclass "
14527                                           "AND deptype = 'e' "
14528                                           "ORDER BY 3,4");
14529
14530         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14531
14532         ntups = PQntuples(res);
14533
14534         i_classid = PQfnumber(res, "classid");
14535         i_objid = PQfnumber(res, "objid");
14536         i_refclassid = PQfnumber(res, "refclassid");
14537         i_refobjid = PQfnumber(res, "refobjid");
14538
14539         /*
14540          * Since we ordered the SELECT by referenced ID, we can expect that
14541          * multiple entries for the same extension will appear together; this
14542          * saves on searches.
14543          */
14544         refdobj = NULL;
14545
14546         for (i = 0; i < ntups; i++)
14547         {
14548                 CatalogId       objId;
14549                 CatalogId       refobjId;
14550
14551                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14552                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14553                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14554                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14555
14556                 if (refdobj == NULL ||
14557                         refdobj->catId.tableoid != refobjId.tableoid ||
14558                         refdobj->catId.oid != refobjId.oid)
14559                         refdobj = findObjectByCatalogId(refobjId);
14560
14561                 /*
14562                  * Failure to find objects mentioned in pg_depend is not unexpected,
14563                  * since for example we don't collect info about TOAST tables.
14564                  */
14565                 if (refdobj == NULL)
14566                 {
14567 #ifdef NOT_USED
14568                         fprintf(stderr, "no referenced object %u %u\n",
14569                                         refobjId.tableoid, refobjId.oid);
14570 #endif
14571                         continue;
14572                 }
14573
14574                 dobj = findObjectByCatalogId(objId);
14575
14576                 if (dobj == NULL)
14577                 {
14578 #ifdef NOT_USED
14579                         fprintf(stderr, "no referencing object %u %u\n",
14580                                         objId.tableoid, objId.oid);
14581 #endif
14582                         continue;
14583                 }
14584
14585                 /* Record dependency so that getDependencies needn't repeat this */
14586                 addObjectDependency(dobj, refdobj->dumpId);
14587
14588                 dobj->ext_member = true;
14589
14590                 /*
14591                  * Normally, mark the member object as not to be dumped.  But in
14592                  * binary upgrades, we still dump the members individually, since the
14593                  * idea is to exactly reproduce the database contents rather than
14594                  * replace the extension contents with something different.
14595                  */
14596                 if (!binary_upgrade)
14597                         dobj->dump = false;
14598                 else
14599                         dobj->dump = refdobj->dump;
14600         }
14601
14602         PQclear(res);
14603
14604         /*
14605          * Now identify extension configuration tables and create TableDataInfo
14606          * objects for them, ensuring their data will be dumped even though the
14607          * tables themselves won't be.
14608          *
14609          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14610          * user data in a configuration table is treated like schema data. This
14611          * seems appropriate since system data in a config table would get
14612          * reloaded by CREATE EXTENSION.
14613          */
14614         for (i = 0; i < numExtensions; i++)
14615         {
14616                 ExtensionInfo *curext = &(extinfo[i]);
14617                 char       *extconfig = curext->extconfig;
14618                 char       *extcondition = curext->extcondition;
14619                 char      **extconfigarray = NULL;
14620                 char      **extconditionarray = NULL;
14621                 int                     nconfigitems;
14622                 int                     nconditionitems;
14623
14624                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14625                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14626                         nconfigitems == nconditionitems)
14627                 {
14628                         int                     j;
14629
14630                         for (j = 0; j < nconfigitems; j++)
14631                         {
14632                                 TableInfo  *configtbl;
14633                                 Oid                     configtbloid = atooid(extconfigarray[j]);
14634                                 bool            dumpobj = curext->dobj.dump;
14635
14636                                 configtbl = findTableByOid(configtbloid);
14637                                 if (configtbl == NULL)
14638                                         continue;
14639
14640                                 /*
14641                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
14642                                  * unless the table or its schema is explicitly included
14643                                  */
14644                                 if (!curext->dobj.dump)
14645                                 {
14646                                         /* check table explicitly requested */
14647                                         if (table_include_oids.head != NULL &&
14648                                                 simple_oid_list_member(&table_include_oids,
14649                                                                                                 configtbloid))
14650                                                 dumpobj = true;
14651
14652                                         /* check table's schema explicitly requested */
14653                                         if (configtbl->dobj.namespace->dobj.dump)
14654                                                 dumpobj = true;
14655                                 }
14656
14657                                 /* check table excluded by an exclusion switch */
14658                                 if (table_exclude_oids.head != NULL &&
14659                                         simple_oid_list_member(&table_exclude_oids,
14660                                                                                         configtbloid))
14661                                         dumpobj = false;
14662
14663                                 /* check schema excluded by an exclusion switch */
14664                                 if (simple_oid_list_member(&schema_exclude_oids,
14665                                         configtbl->dobj.namespace->dobj.catId.oid))
14666                                         dumpobj = false;
14667
14668                                 if (dumpobj)
14669                                 {
14670                                         /*
14671                                          * Note: config tables are dumped without OIDs regardless of
14672                                          * the --oids setting.  This is because row filtering
14673                                          * conditions aren't compatible with dumping OIDs.
14674                                          */
14675                                         makeTableDataInfo(configtbl, false);
14676                                         if (configtbl->dataObj != NULL)
14677                                         {
14678                                                 if (strlen(extconditionarray[j]) > 0)
14679                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14680                                         }
14681                                 }
14682                         }
14683                 }
14684                 if (extconfigarray)
14685                         free(extconfigarray);
14686                 if (extconditionarray)
14687                         free(extconditionarray);
14688         }
14689
14690         destroyPQExpBuffer(query);
14691 }
14692
14693 /*
14694  * getDependencies --- obtain available dependency data
14695  */
14696 static void
14697 getDependencies(Archive *fout)
14698 {
14699         PQExpBuffer query;
14700         PGresult   *res;
14701         int                     ntups,
14702                                 i;
14703         int                     i_classid,
14704                                 i_objid,
14705                                 i_refclassid,
14706                                 i_refobjid,
14707                                 i_deptype;
14708         DumpableObject *dobj,
14709                            *refdobj;
14710
14711         /* No dependency info available before 7.3 */
14712         if (fout->remoteVersion < 70300)
14713                 return;
14714
14715         if (g_verbose)
14716                 write_msg(NULL, "reading dependency data\n");
14717
14718         /* Make sure we are in proper schema */
14719         selectSourceSchema(fout, "pg_catalog");
14720
14721         query = createPQExpBuffer();
14722
14723         /*
14724          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14725          * already processed by getExtensionMembership.
14726          */
14727         appendPQExpBuffer(query, "SELECT "
14728                                           "classid, objid, refclassid, refobjid, deptype "
14729                                           "FROM pg_depend "
14730                                           "WHERE deptype != 'p' AND deptype != 'e' "
14731                                           "ORDER BY 1,2");
14732
14733         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14734
14735         ntups = PQntuples(res);
14736
14737         i_classid = PQfnumber(res, "classid");
14738         i_objid = PQfnumber(res, "objid");
14739         i_refclassid = PQfnumber(res, "refclassid");
14740         i_refobjid = PQfnumber(res, "refobjid");
14741         i_deptype = PQfnumber(res, "deptype");
14742
14743         /*
14744          * Since we ordered the SELECT by referencing ID, we can expect that
14745          * multiple entries for the same object will appear together; this saves
14746          * on searches.
14747          */
14748         dobj = NULL;
14749
14750         for (i = 0; i < ntups; i++)
14751         {
14752                 CatalogId       objId;
14753                 CatalogId       refobjId;
14754                 char            deptype;
14755
14756                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14757                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14758                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14759                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14760                 deptype = *(PQgetvalue(res, i, i_deptype));
14761
14762                 if (dobj == NULL ||
14763                         dobj->catId.tableoid != objId.tableoid ||
14764                         dobj->catId.oid != objId.oid)
14765                         dobj = findObjectByCatalogId(objId);
14766
14767                 /*
14768                  * Failure to find objects mentioned in pg_depend is not unexpected,
14769                  * since for example we don't collect info about TOAST tables.
14770                  */
14771                 if (dobj == NULL)
14772                 {
14773 #ifdef NOT_USED
14774                         fprintf(stderr, "no referencing object %u %u\n",
14775                                         objId.tableoid, objId.oid);
14776 #endif
14777                         continue;
14778                 }
14779
14780                 refdobj = findObjectByCatalogId(refobjId);
14781
14782                 if (refdobj == NULL)
14783                 {
14784 #ifdef NOT_USED
14785                         fprintf(stderr, "no referenced object %u %u\n",
14786                                         refobjId.tableoid, refobjId.oid);
14787 #endif
14788                         continue;
14789                 }
14790
14791                 /*
14792                  * Ordinarily, table rowtypes have implicit dependencies on their
14793                  * tables.      However, for a composite type the implicit dependency goes
14794                  * the other way in pg_depend; which is the right thing for DROP but
14795                  * it doesn't produce the dependency ordering we need. So in that one
14796                  * case, we reverse the direction of the dependency.
14797                  */
14798                 if (deptype == 'i' &&
14799                         dobj->objType == DO_TABLE &&
14800                         refdobj->objType == DO_TYPE)
14801                         addObjectDependency(refdobj, dobj->dumpId);
14802                 else
14803                         /* normal case */
14804                         addObjectDependency(dobj, refdobj->dumpId);
14805         }
14806
14807         PQclear(res);
14808
14809         destroyPQExpBuffer(query);
14810 }
14811
14812
14813 /*
14814  * createBoundaryObjects - create dummy DumpableObjects to represent
14815  * dump section boundaries.
14816  */
14817 static DumpableObject *
14818 createBoundaryObjects(void)
14819 {
14820         DumpableObject *dobjs;
14821
14822         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
14823
14824         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
14825         dobjs[0].catId = nilCatalogId;
14826         AssignDumpId(dobjs + 0);
14827         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
14828
14829         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
14830         dobjs[1].catId = nilCatalogId;
14831         AssignDumpId(dobjs + 1);
14832         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
14833
14834         return dobjs;
14835 }
14836
14837 /*
14838  * addBoundaryDependencies - add dependencies as needed to enforce the dump
14839  * section boundaries.
14840  */
14841 static void
14842 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
14843                                                 DumpableObject *boundaryObjs)
14844 {
14845         DumpableObject *preDataBound = boundaryObjs + 0;
14846         DumpableObject *postDataBound = boundaryObjs + 1;
14847         int                     i;
14848
14849         for (i = 0; i < numObjs; i++)
14850         {
14851                 DumpableObject *dobj = dobjs[i];
14852
14853                 /*
14854                  * The classification of object types here must match the SECTION_xxx
14855                  * values assigned during subsequent ArchiveEntry calls!
14856                  */
14857                 switch (dobj->objType)
14858                 {
14859                         case DO_NAMESPACE:
14860                         case DO_EXTENSION:
14861                         case DO_TYPE:
14862                         case DO_SHELL_TYPE:
14863                         case DO_FUNC:
14864                         case DO_AGG:
14865                         case DO_OPERATOR:
14866                         case DO_OPCLASS:
14867                         case DO_OPFAMILY:
14868                         case DO_COLLATION:
14869                         case DO_CONVERSION:
14870                         case DO_TABLE:
14871                         case DO_ATTRDEF:
14872                         case DO_PROCLANG:
14873                         case DO_CAST:
14874                         case DO_DUMMY_TYPE:
14875                         case DO_TSPARSER:
14876                         case DO_TSDICT:
14877                         case DO_TSTEMPLATE:
14878                         case DO_TSCONFIG:
14879                         case DO_FDW:
14880                         case DO_FOREIGN_SERVER:
14881                         case DO_BLOB:
14882                                 /* Pre-data objects: must come before the pre-data boundary */
14883                                 addObjectDependency(preDataBound, dobj->dumpId);
14884                                 break;
14885                         case DO_TABLE_DATA:
14886                         case DO_BLOB_DATA:
14887                                 /* Data objects: must come between the boundaries */
14888                                 addObjectDependency(dobj, preDataBound->dumpId);
14889                                 addObjectDependency(postDataBound, dobj->dumpId);
14890                                 break;
14891                         case DO_INDEX:
14892                         case DO_REFRESH_MATVIEW:
14893                         case DO_TRIGGER:
14894                         case DO_EVENT_TRIGGER:
14895                         case DO_DEFAULT_ACL:
14896                                 /* Post-data objects: must come after the post-data boundary */
14897                                 addObjectDependency(dobj, postDataBound->dumpId);
14898                                 break;
14899                         case DO_RULE:
14900                                 /* Rules are post-data, but only if dumped separately */
14901                                 if (((RuleInfo *) dobj)->separate)
14902                                         addObjectDependency(dobj, postDataBound->dumpId);
14903                                 break;
14904                         case DO_CONSTRAINT:
14905                         case DO_FK_CONSTRAINT:
14906                                 /* Constraints are post-data, but only if dumped separately */
14907                                 if (((ConstraintInfo *) dobj)->separate)
14908                                         addObjectDependency(dobj, postDataBound->dumpId);
14909                                 break;
14910                         case DO_PRE_DATA_BOUNDARY:
14911                                 /* nothing to do */
14912                                 break;
14913                         case DO_POST_DATA_BOUNDARY:
14914                                 /* must come after the pre-data boundary */
14915                                 addObjectDependency(dobj, preDataBound->dumpId);
14916                                 break;
14917                 }
14918         }
14919 }
14920
14921
14922 /*
14923  * BuildArchiveDependencies - create dependency data for archive TOC entries
14924  *
14925  * The raw dependency data obtained by getDependencies() is not terribly
14926  * useful in an archive dump, because in many cases there are dependency
14927  * chains linking through objects that don't appear explicitly in the dump.
14928  * For example, a view will depend on its _RETURN rule while the _RETURN rule
14929  * will depend on other objects --- but the rule will not appear as a separate
14930  * object in the dump.  We need to adjust the view's dependencies to include
14931  * whatever the rule depends on that is included in the dump.
14932  *
14933  * Just to make things more complicated, there are also "special" dependencies
14934  * such as the dependency of a TABLE DATA item on its TABLE, which we must
14935  * not rearrange because pg_restore knows that TABLE DATA only depends on
14936  * its table.  In these cases we must leave the dependencies strictly as-is
14937  * even if they refer to not-to-be-dumped objects.
14938  *
14939  * To handle this, the convention is that "special" dependencies are created
14940  * during ArchiveEntry calls, and an archive TOC item that has any such
14941  * entries will not be touched here.  Otherwise, we recursively search the
14942  * DumpableObject data structures to build the correct dependencies for each
14943  * archive TOC item.
14944  */
14945 static void
14946 BuildArchiveDependencies(Archive *fout)
14947 {
14948         ArchiveHandle *AH = (ArchiveHandle *) fout;
14949         TocEntry   *te;
14950
14951         /* Scan all TOC entries in the archive */
14952         for (te = AH->toc->next; te != AH->toc; te = te->next)
14953         {
14954                 DumpableObject *dobj;
14955                 DumpId     *dependencies;
14956                 int                     nDeps;
14957                 int                     allocDeps;
14958
14959                 /* No need to process entries that will not be dumped */
14960                 if (te->reqs == 0)
14961                         continue;
14962                 /* Ignore entries that already have "special" dependencies */
14963                 if (te->nDeps > 0)
14964                         continue;
14965                 /* Otherwise, look up the item's original DumpableObject, if any */
14966                 dobj = findObjectByDumpId(te->dumpId);
14967                 if (dobj == NULL)
14968                         continue;
14969                 /* No work if it has no dependencies */
14970                 if (dobj->nDeps <= 0)
14971                         continue;
14972                 /* Set up work array */
14973                 allocDeps = 64;
14974                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
14975                 nDeps = 0;
14976                 /* Recursively find all dumpable dependencies */
14977                 findDumpableDependencies(AH, dobj,
14978                                                                  &dependencies, &nDeps, &allocDeps);
14979                 /* And save 'em ... */
14980                 if (nDeps > 0)
14981                 {
14982                         dependencies = (DumpId *) pg_realloc(dependencies,
14983                                                                                                  nDeps * sizeof(DumpId));
14984                         te->dependencies = dependencies;
14985                         te->nDeps = nDeps;
14986                 }
14987                 else
14988                         free(dependencies);
14989         }
14990 }
14991
14992 /* Recursive search subroutine for BuildArchiveDependencies */
14993 static void
14994 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
14995                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
14996 {
14997         int                     i;
14998
14999         /*
15000          * Ignore section boundary objects: if we search through them, we'll
15001          * report lots of bogus dependencies.
15002          */
15003         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15004                 dobj->objType == DO_POST_DATA_BOUNDARY)
15005                 return;
15006
15007         for (i = 0; i < dobj->nDeps; i++)
15008         {
15009                 DumpId          depid = dobj->dependencies[i];
15010
15011                 if (TocIDRequired(AH, depid) != 0)
15012                 {
15013                         /* Object will be dumped, so just reference it as a dependency */
15014                         if (*nDeps >= *allocDeps)
15015                         {
15016                                 *allocDeps *= 2;
15017                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15018                                                                                                 *allocDeps * sizeof(DumpId));
15019                         }
15020                         (*dependencies)[*nDeps] = depid;
15021                         (*nDeps)++;
15022                 }
15023                 else
15024                 {
15025                         /*
15026                          * Object will not be dumped, so recursively consider its deps. We
15027                          * rely on the assumption that sortDumpableObjects already broke
15028                          * any dependency loops, else we might recurse infinitely.
15029                          */
15030                         DumpableObject *otherdobj = findObjectByDumpId(depid);
15031
15032                         if (otherdobj)
15033                                 findDumpableDependencies(AH, otherdobj,
15034                                                                                  dependencies, nDeps, allocDeps);
15035                 }
15036         }
15037 }
15038
15039
15040 /*
15041  * selectSourceSchema - make the specified schema the active search path
15042  * in the source database.
15043  *
15044  * NB: pg_catalog is explicitly searched after the specified schema;
15045  * so user names are only qualified if they are cross-schema references,
15046  * and system names are only qualified if they conflict with a user name
15047  * in the current schema.
15048  *
15049  * Whenever the selected schema is not pg_catalog, be careful to qualify
15050  * references to system catalogs and types in our emitted commands!
15051  *
15052  * This function is called only from selectSourceSchemaOnAH and
15053  * selectSourceSchema.
15054  */
15055 static void
15056 selectSourceSchema(Archive *fout, const char *schemaName)
15057 {
15058         PQExpBuffer query;
15059
15060         /* This is checked by the callers already */
15061         Assert(schemaName != NULL && *schemaName != '\0');
15062
15063         /* Not relevant if fetching from pre-7.3 DB */
15064         if (fout->remoteVersion < 70300)
15065                 return;
15066
15067         query = createPQExpBuffer();
15068         appendPQExpBuffer(query, "SET search_path = %s",
15069                                           fmtId(schemaName));
15070         if (strcmp(schemaName, "pg_catalog") != 0)
15071                 appendPQExpBuffer(query, ", pg_catalog");
15072
15073         ExecuteSqlStatement(fout, query->data);
15074
15075         destroyPQExpBuffer(query);
15076 }
15077
15078 /*
15079  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15080  * given type name.
15081  *
15082  * NB: in 7.3 and up the result may depend on the currently-selected
15083  * schema; this is why we don't try to cache the names.
15084  */
15085 static char *
15086 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15087 {
15088         char       *result;
15089         PQExpBuffer query;
15090         PGresult   *res;
15091
15092         if (oid == 0)
15093         {
15094                 if ((opts & zeroAsOpaque) != 0)
15095                         return pg_strdup(g_opaque_type);
15096                 else if ((opts & zeroAsAny) != 0)
15097                         return pg_strdup("'any'");
15098                 else if ((opts & zeroAsStar) != 0)
15099                         return pg_strdup("*");
15100                 else if ((opts & zeroAsNone) != 0)
15101                         return pg_strdup("NONE");
15102         }
15103
15104         query = createPQExpBuffer();
15105         if (fout->remoteVersion >= 70300)
15106         {
15107                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15108                                                   oid);
15109         }
15110         else if (fout->remoteVersion >= 70100)
15111         {
15112                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15113                                                   oid);
15114         }
15115         else
15116         {
15117                 appendPQExpBuffer(query, "SELECT typname "
15118                                                   "FROM pg_type "
15119                                                   "WHERE oid = '%u'::oid",
15120                                                   oid);
15121         }
15122
15123         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15124
15125         if (fout->remoteVersion >= 70100)
15126         {
15127                 /* already quoted */
15128                 result = pg_strdup(PQgetvalue(res, 0, 0));
15129         }
15130         else
15131         {
15132                 /* may need to quote it */
15133                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15134         }
15135
15136         PQclear(res);
15137         destroyPQExpBuffer(query);
15138
15139         return result;
15140 }
15141
15142 /*
15143  * myFormatType --- local implementation of format_type for use with 7.0.
15144  */
15145 static char *
15146 myFormatType(const char *typname, int32 typmod)
15147 {
15148         char       *result;
15149         bool            isarray = false;
15150         PQExpBuffer buf = createPQExpBuffer();
15151
15152         /* Handle array types */
15153         if (typname[0] == '_')
15154         {
15155                 isarray = true;
15156                 typname++;
15157         }
15158
15159         /* Show lengths on bpchar and varchar */
15160         if (strcmp(typname, "bpchar") == 0)
15161         {
15162                 int                     len = (typmod - VARHDRSZ);
15163
15164                 appendPQExpBuffer(buf, "character");
15165                 if (len > 1)
15166                         appendPQExpBuffer(buf, "(%d)",
15167                                                           typmod - VARHDRSZ);
15168         }
15169         else if (strcmp(typname, "varchar") == 0)
15170         {
15171                 appendPQExpBuffer(buf, "character varying");
15172                 if (typmod != -1)
15173                         appendPQExpBuffer(buf, "(%d)",
15174                                                           typmod - VARHDRSZ);
15175         }
15176         else if (strcmp(typname, "numeric") == 0)
15177         {
15178                 appendPQExpBuffer(buf, "numeric");
15179                 if (typmod != -1)
15180                 {
15181                         int32           tmp_typmod;
15182                         int                     precision;
15183                         int                     scale;
15184
15185                         tmp_typmod = typmod - VARHDRSZ;
15186                         precision = (tmp_typmod >> 16) & 0xffff;
15187                         scale = tmp_typmod & 0xffff;
15188                         appendPQExpBuffer(buf, "(%d,%d)",
15189                                                           precision, scale);
15190                 }
15191         }
15192
15193         /*
15194          * char is an internal single-byte data type; Let's make sure we force it
15195          * through with quotes. - thomas 1998-12-13
15196          */
15197         else if (strcmp(typname, "char") == 0)
15198                 appendPQExpBuffer(buf, "\"char\"");
15199         else
15200                 appendPQExpBuffer(buf, "%s", fmtId(typname));
15201
15202         /* Append array qualifier for array types */
15203         if (isarray)
15204                 appendPQExpBuffer(buf, "[]");
15205
15206         result = pg_strdup(buf->data);
15207         destroyPQExpBuffer(buf);
15208
15209         return result;
15210 }
15211
15212 /*
15213  * Return a column list clause for the given relation.
15214  *
15215  * Special case: if there are no undropped columns in the relation, return
15216  * "", not an invalid "()" column list.
15217  */
15218 static const char *
15219 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15220 {
15221         int                     numatts = ti->numatts;
15222         char      **attnames = ti->attnames;
15223         bool       *attisdropped = ti->attisdropped;
15224         bool            needComma;
15225         int                     i;
15226
15227         appendPQExpBuffer(buffer, "(");
15228         needComma = false;
15229         for (i = 0; i < numatts; i++)
15230         {
15231                 if (attisdropped[i])
15232                         continue;
15233                 if (needComma)
15234                         appendPQExpBuffer(buffer, ", ");
15235                 appendPQExpBuffer(buffer, "%s", fmtId(attnames[i]));
15236                 needComma = true;
15237         }
15238
15239         if (!needComma)
15240                 return "";                              /* no undropped columns */
15241
15242         appendPQExpBuffer(buffer, ")");
15243         return buffer->data;
15244 }
15245
15246 /*
15247  * Execute an SQL query and verify that we got exactly one row back.
15248  */
15249 static PGresult *
15250 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15251 {
15252         PGresult   *res;
15253         int                     ntups;
15254
15255         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15256
15257         /* Expecting a single result only */
15258         ntups = PQntuples(res);
15259         if (ntups != 1)
15260                 exit_horribly(NULL,
15261                                           ngettext("query returned %d row instead of one: %s\n",
15262                                                            "query returned %d rows instead of one: %s\n",
15263                                                            ntups),
15264                                           ntups, query);
15265
15266         return res;
15267 }